我们需要在 gem 中实现需要将代码片段全局注入到 Thread.new 块语句中的功能。让我们在这里讨论为什么:)
如果我定义类似的东西:
module MyThread
def new(*args, &block)
puts "i'm in Thread.new"
super(*args, &block)
end
end
Thread.singleton_class.prepend MyThread
然后创建:
t = Thread.new {
puts "I'm async thread"
}
t.join
我会看到两条已发布的消息。问题是我需要将一些东西从主线程传递到新线程,所以在这种情况下我需要修改块是有问题的。如果没有它,即使我将某些内容放入 MyThread.new 中,它也只会在主线程中执行。通常我可以通过阅读 ruby 代码来逆向工程这些东西,但是 Thread 没有在 ruby 中定义,它是纯 C api,在 ruby 中没有任何包装器,正如我所见。
所以问题是是否有任何选项可以将某些内容从主线程全局传递到新线程,并在新线程代码中定义将在那里包装块。可能不是没有真正肮脏的黑客,但也许我错过了一些东西。
提前谢谢!
如果我正确理解你的问题,你的模块“注入”的代码在主线程中运行:(我稍微简化了你的代码以修补
#initialize
而不是.new
)
module MyThread
def initialize(*args, &block)
puts "Module is #{Thread.current}"
super(*args, &block)
end
end
Thread.prepend MyThread
puts " Main is #{Thread.current}"
Thread.new { puts " Block is #{Thread.current}" }.join
输出:
Main is #<Thread:0x00007f88e807bc78 run>
Module is #<Thread:0x00007f88e807bc78 run>
Block is #<Thread:0x00007f88e20cc7c8 test.rb:10 run>
...但你希望它在另一个线程中运行,就像块一样。
为此,您必须将其移至您传递给
super
的块中。由于您无法修改 block
参数,因此您必须创建一个新块并从内部调用传递的块:
module MyThread
def initialize(*args, &block)
super do |*inner_args|
puts "Module is #{Thread.current}"
block.call(*inner_args)
end
end
end
Thread.prepend MyThread
puts " Main is #{Thread.current}"
Thread.new { puts " Block is #{Thread.current}" }.join
输出:
Main is #<Thread:0x00007f927907bc88 run>
Module is #<Thread:0x00007f926203fb50 test.rb:3 run>
Block is #<Thread:0x00007f926203fb50 test.rb:3 run>