【问题标题】:How to pass a block to a yielding thread in Ruby如何将块传递给Ruby中的产生线程
【发布时间】:2018-08-07 17:30:21
【问题描述】:

我正在尝试围绕 Ruby 中的线程和 Yielding 进行研究,但我有一个关于如何将块传递给 yield 线程的问题。

具体来说,我有一个正在休眠的线程,等待被告知做某事,如果被告知,我希望该线程执行不同的块(即,它正在休眠,并且如果用户按下按钮,除了睡觉做点什么)。

假设我有这样的代码:

window = Thread.new do 

  @thread1 = Thread.new do
    # Do some cool stuff

    # Decide it is time to sleep
    until @told_to_wakeup
       if block_given?
         yield
       end
       sleep(1)
    end

  # At some point after @thread1 starts sleeping, 
  # a user might do something, so I want to execute
  # some code in @@thread1 (unfortunately spawning a new thread
  # won't work correctly in my case)

end

有可能吗?

我尝试使用 @@thread1.send(),但 send 正在寻找方法名称。

感谢您抽出宝贵时间查看此内容!

【问题讨论】:

  • 听起来你需要一个事件循环。看看使用Queue 处理信号线程。
  • 我快速浏览了 Queue,但看起来该块不会在 thread1 中执行。在这种情况下,我基本上需要 thread1 来执行我传递给它的块,其他任何执行块的东西都不能正常工作(所有这些都与 thread1 在代码的其他部分中的使用方式有关)

标签: ruby multithreading yield


【解决方案1】:

这是一个简单的工作线程:

queue = Queue.new

worker = Thread.new do
  # Fetch an item from the work queue, or wait until one is available
  while (work = queue.pop)
    # ... Do something with work
  end
end

queue.push(thing: 'to do')

pop 方法将阻塞,直到有东西被推入队列。

当你完成后,你可以故意推入一个空的工作:

queue.push(nil)

这将使工作线程退出。

您始终可以扩展该功能以执行更多操作或处理更多条件。

【讨论】:

  • 感谢您抽出宝贵时间对此进行调查。我在玩代码,但它仍然不能满足我的需要。这是我所拥有的:repl.it/repls/TroubledPunyAdmins 问题是Task1 没有停止并让Task2 执行,Task1 仍在休眠。对于更多上下文,Task1 正在根据用户操作(例如:按下按钮)执行,并且它正在等待另一个按钮按下。但是,UI 之外的某些内容可能会触发操作/更改,并且如果原始线程未运行代码,它将不会向用户显示正在发生的事情。
  • 需要考虑两件事。首先,转向event loop 设计模式并让您的工作循环执行不会长时间阻塞或停止的短而快速的操作。在其中引入sleep 会导致它停止处理其他事件,这很糟糕。如有必要,启动后台线程或使用计时器。
  • 其次,始终始终避免将任意代码块作为字符串传递给eval。在 Ruby 中,很容易传入 Proc:queue.push(-> { do ... stuff. }),其中内部是实际的 Ruby 代码,而不是字符串。这也有助于解决绑定问题,因为您可以有一个适当的闭包,这是字符串无法做到的。
猜你喜欢
  • 2019-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-04
  • 1970-01-01
  • 2019-11-06
  • 2011-06-07
  • 2014-01-05
相关资源
最近更新 更多