简体   繁体   English

Ruby中的Fibers有什么意义?

[英]What is the point of Fibers in Ruby?

I don't understand how the below: 我不明白如下:

counts = Hash.new(0)

File.foreach("testfile") do |line|
  line.scan(/\w+/) do |word|
    word = word.downcase
    counts[word] += 1
  end
end

counts.keys.sort.each {|k| print "#{k}:#{counts[k]} "}

Is so much worse than: 比这更糟糕的是:

words = Fiber.new do
  File.foreach("testfile") do |line|
    line.scan(/\w+/) do |word|
      Fiber.yield word.downcase
    end
  end
end

counts = Hash.new(0)

while word = words.resume
  counts[word] += 1
end

counts.keys.sort.each {|k| print "#{k}:#{counts[k]} "}

Fibers are a way of suspending and resuming arbitrary blocks of code. 光纤是一种暂停和恢复任意代码块的方法。 An example like this isn't really a great use-case as it doesn't offer any real advantage over the traditional way of reading in lines and processing them. 像这样的例子并不是一个很好的用例,因为它没有提供任何真正的优势,而不是传统的阅读和处理方式。

In this particular example, if you wanted to make it better, you'd write an enumerator-style interface so you could write: 在这个特定的例子中,如果你想让它变得更好,你可以编写一个枚举器风格的接口,这样你就可以编写:

words = WordsReader.new("testfile")

words.each do |word|
  # ...
end

Where Fibers become important is in writing asynchronous code. 纤维变得重要的地方在于编写异步代码。 For example, inside the EventMachine environment you need to be able to issue an asynchronous call, suspend a block of code, and resume it when you receive the response. 例如,在EventMachine环境中,您需要能够发出异步调用,挂起代码块,并在收到响应时恢复它。

This ends up looking like this: 最终看起来像这样:

async_call(argument1, argument2) do |response_1|
  if (response_1.ok?)
    async_call(argument3, argument4) do |response_2|
      if (response_2.ok?)
        async_call(argument5, argument6) do |response_3|
          if (response_3.ok?)
            do_something(response_1, response_2, response_3)
          else
            panic_and_fail!
          end
        end
      else
        panic_and_fail!
      end
    end
  else
    panic_and_fail!
  end
end

This sort of nested, nested and re-nested call structure is loosely termed "callback hell" as it gets very difficult to manage once your logic becomes non-trivial. 这种嵌套,嵌套和重新嵌套的调用结构被称为“回调地狱”,因为一旦你的逻辑变得非常重要,它就很难管理。 One way to flatten this structure is to employ Fibers. 平整这种结构的一种方法是使用纤维。 A properly Fiber-ized equivalent is: 适当的纤维化等效物是:

begin
  response_1 = fiber_call(argument1, argument2)
  response_2 = fiber_call(argument3, argument4)
  response_3 = fiber_call(argument5, argument6)

  do_something(response_1, response_2, response_3)

rescue NotOkay
  panic_and_fail!
end

Fibers can take advantage of exceptions, where callback-type code cannot. 光纤可以利用异常,其中回调类型代码不能。 Exceptions, when used effectively, can massively simplify a block of code, as you can see here. 有效使用时,例外可以大规模简化代码块,如您在此处所见。 Instead of testing for ok? 而不是测试ok? on each response, it's expected that the call will throw an exception of type NotOkay instead. 在每个响应中,预计该调用将抛出NotOkay类型的异常。

Callbacks cannot reliably throw exceptions since the initiator of the call has already fallen out of scope when the callback occurs. 回调不能可靠地抛出异常,因为在回调发生时,调用的发起者已经超出了范围。 This is a fundamental limitation of asynchronous programming with callbacks. 这是使用回调进行异步编程的基本限制。 Fiber driven code maintains a proper call stack, it's merely suspended and resumed as-is, so exceptions properly cascade through the caller. 光纤驱动的代码维护一个正确的调用堆栈,它只是暂停并按原样恢复,因此异常正确地级联通过调用者。

I've found Fibers to be both simple to understand and very difficult to apply correctly. 我发现Fibers既易于理解又很难正确应用。 Most of the time you won't have to use them directly, you'll be using a library that employs them instead. 大多数情况下,您不必直接使用它们,您将使用一个使用它们的库。 Writing "Fiber-aware" code is not unlike writing "Thread-safe" code. 编写“光纤感知”代码与编写“线程安全”代码没有什么不同。 It can be tricky to get right. 做对可能很棘手。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM