使用光纤时的意外结果

  • 本文关键字:意外 结果 光纤 ruby
  • 更新时间 :
  • 英文 :


我写了一个简单的ruby光纤程序来看看它们是如何工作的,并得到了一个意想不到的结果。

#! /usr/bin/env ruby
#encoding: utf-8
#frozen_string_literal: true
sg = Fiber.new do
File.open(begin print "Enter filename: "; gets.chomp end).each{|l| Fiber.yield l}
end
begin
loop do
puts sg.resume
end
rescue => err
puts "Error: #{err.message}"
end

功能

This is the first
This is the second
This is the third
This is the fourth
This is the fifth

和上面程序的输出

Enter filename: datafile
This is the first
This is the second
This is the third
This is the fourth
This is the fifth
#<File:0x0000557ce26ce3c8>
Error: attempt to resume a terminated fiber

我不知道为什么它在输出中显示#File:0x0000557ce26ce3c8。

说明:ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux-gnu]

从文档,

在生成或终止时,Fiber返回最后一次执行的表达式的值

除了Fiber.yield调用之外,光纤(像普通函数一样)返回光纤中最终表达式的结果。

你的纤维体是这样的。

File.open(begin print "Enter filename: "; gets.chomp end).each{|l| Fiber.yield l}

.each中,生成文件的每一行,正如您已经观察到的那样打印出来。但是,当纤维完成后,它产生一个最终值,这是File.open的结果。File.open返回File对象本身。所以你的sg.resume实际上看到了六个结果,而不是五个。

"This is the first"
"This is the second"
"This is the third"
"This is the fourth"
"This is the fifth"
(the file object itself)

这实际上指出了程序开始时的一个小问题:您从不关闭文件。您可以使用File#close或通过将块传递给File::open来做到这一点。为了完全安全,你的纤维代码应该看起来像这样。

sg = Fiber.new do
print "Enter filename: "
filename = gets.chomp
# By passing File.open a block, the file is closed after the block automatically.
File.open(filename) do |f|
f.each{|l| Fiber.yield l}
end
# Our fiber has to return something at the end, so let's just return nil
nil
end
begin
loop do
# Get the value. If it's nil, then we're done; we can break out of the loop.
# Otherwise, print it
value = sg.resume
break if value.nil?
puts value
end
rescue => err
puts "Error: #{err.message}"
end

现在,除了处理那个讨厌的文件句柄之外,我们还有一种方法来检测光纤何时结束,并且我们不再收到"尝试恢复已终止的光纤"的消息。错误。

最新更新