【问题标题】:Using Fibers to create a REPL使用 Fibers 创建 REPL
【发布时间】:2013-10-10 07:06:27
【问题描述】:

我正在尝试使用 Ruby 的 Fibers 创建一个 REPL,其中一根 Fiber 作为前端——接收输入并显示输出——另一根 Fiber 作为后端——处理来自前端的输入并返回输出以供显示。

(我这样做部分是因为我隐约需要一个 REPL,部分是因为我想了解 Fibers,部分是因为我认为这将允许测试 - 只需替换测试框架中的前端来测试后端,反之亦然- 反之)。

麻烦的是,我找不到任何关于如何实际使用完整 Fibers 库的好的文档,而且我最初的猜测是行不通的。所以,我有四个问题:

  1. 这是一个半途而废的想法吗?尝试从 Fibers 制作 REPL 会遇到很大的麻烦吗?
  2. 如果没有 Fibers 库,我认为我无法做到这一点,因为我需要双向传递值。对吗?
  3. 谁能给我指点关于 Ruby Fibers 的体面的入门教程或文档(如在库中,而不是单向生成器的东西)?
  4. 为什么以下操作不起作用?正确显示Enter a string:,并反复接受输入;但每次我提供一行输入时,它只会显示 first 行输入反转(包括示例输出,以防不清楚)。

代码:

require 'fiber'


# Simple REPL. Echo back the user's input, reversed, until they
# enter "pots" (resulting in "stop")
frontend = Fiber.new do |backend, output|
  while output != 'stop' do
    puts output
    print ": "
    input = gets
    output = backend.transfer(frontend, input)
  end
end

backend = Fiber.new do |frontend, input|
  loop do
    frontend.transfer(input.reverse)
  end
end

frontend.transfer(backend, "Enter a string:")

输出:

Enter a string:
: Hello

olleH
: World

olleH
:

【问题讨论】:

    标签: ruby read-eval-print-loop fibers


    【解决方案1】:

    按顺序回答:

    1. 光纤不适合这个。光纤是一个非常高级的特性,用于协作并发。将它们用于由函数和块覆盖的简单用例是没有意义的。
    2. 没有。查看您的 REPL,仅使用方法编写:

      def repl(output, &backend)
        input = nil
        while output != "stop"
          puts output
          print ': '
          input = gets.chomp
          output = backend.call(input)
        end
      end
      repl("Enter a string: ") {|input| input.reverse}
      

      哪些输出:

      Enter a string:                                                                                                                      
      : Hi                                                                                                                                 
      iH                                                                                                                                   
      : Hello                                                                                                                              
      olleH
      : Bork
      kroB
      

      完美运行。

    3. Ruby 自己的文档:http://ruby-doc.org/core-2.0.0/Fiber.html

    4. 当您多次调用transferresume 时,参数仅在第一次传递给光纤块。因此,每次您调用transfer 时,支持的光纤仍在反转它通过的第一根字符串,因为它从未得到另一根。这就是为什么纤维在实现这一点时是错误的。

    【讨论】:

    • 啊,答案 3 很有帮助;将我的后端更改为包含 _, input = frontend.transfer(input.reverse) 使其正常工作。我很感兴趣是什么让 Fibers 不适合这里; AIUI,当您有两个“进程”时使用它们,每个进程都需要阻止等待来自另一个的数据。怎么不是这种情况?仅仅是复杂性不够的问题吗?
    • @Chowlett:正是这种情况,但缺少关键部分。您的前端和后端不是进程。他们没有改变状态,没有状态可以改变多个请求。如果你的后端是一个 irb 后端,那它可能是一个纤程,因为它是一个有状态的进程。但是前端呢?那里根本没有儿子州。
    • 很公平,感谢您的澄清。 FWIW,我的后端需要有状态;但我的前端不太可能,所以我将寻求一个更简单的解决方案。
    • @Chowlett:很高兴我能帮上忙
    猜你喜欢
    • 2016-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 2011-04-17
    • 1970-01-01
    • 2019-01-27
    • 1970-01-01
    相关资源
    最近更新 更多