在 ruby Thread 对象中包装代码块

问题描述 投票:0回答:1

我们需要在 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 中没有任何包装器,正如我所见。

所以问题是是否有任何选项可以将某些内容从主线程全局传递到新线程,并在新线程代码中定义将在那里包装块。可能不是没有真正肮脏的黑客,但也许我错过了一些东西。

提前谢谢!

ruby-on-rails ruby multithreading metaprogramming
1个回答
0
投票

如果我正确理解你的问题,你的模块“注入”的代码在主线程中运行:(我稍微简化了你的代码以修补

#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>
© www.soinside.com 2019 - 2024. All rights reserved.