gri*_*yvp 17 ruby multithreading ruby-1.9
Ruby 1.9应该具有本机线程,如果某些线程进入本机代码(如GUI工具包主循环或某些Ruby lib的C实现),GIL应该会解除.
但是,如果我开始关注在主线程中显示GUI的简单代码示例并在单独的线程中执行一些基本的数学运算 - GUI将严重挂起,尝试调整窗口大小以便自己查看.我已经检查过不同的GUI工具包,Qt(qtbindings gem) - 它的行为完全相同.在Windows 7和OSX 10.7上使用Ruby 1.9.3-p0进行了测试
require 'tk'
require 'thread'
Thread.new { loop { a = 1 } }
TkRoot.new.mainloop()
Run Code Online (Sandbox Code Playgroud)
Python中的相同代码工作正常,没有任何GUI挂起:
from Tkinter import *
from threading import *
class WorkThread( Thread ) :
def run( self ) :
while True :
a = 1
WorkThread().start()
Tk().mainloop()
Run Code Online (Sandbox Code Playgroud)
我做错了什么?
UPDATE
看来在Ubuntu linux上没有这样的问题,所以我的问题主要是关于Windows和OSX.
UPDATE
有人指出OSX上没有这样的问题.所以我汇编了一个分步和重现问题的分步指南:


test.rb使用我的示例中的代码创建一个文件并运行它.尝试调整窗口大小 - 你会看到可怕的滞后.从代码中删除线程,启动并尝试调整窗口大小 - 滞后消失.我录制了这个测试的视频.Ruby编译命令:
./configure --with-arch=x86_64,i386 --enable-pthread --enable-shared --with-gcc=clang --prefix=/usr
make
sudo make install
Run Code Online (Sandbox Code Playgroud)
Cor*_*ren 11
这种挂起可能是由Toolkit中的Ruby绑定的C代码引起的.如您所知,ruby线程具有全局锁定:GIL.似乎Ruby绑定的C线程,Tk C线程和Pure Ruby线程之间的混合并不顺利.
针对类似案例有一个记录的解决方法,您可以尝试在之前添加这些行require 'tk':
module TkCore
RUN_EVENTLOOP_ON_MAIN_THREAD = true
end
Run Code Online (Sandbox Code Playgroud)
图形工具包需要一个主线程才能刷新图形元素.如果您的线程处于密集计算中,那么您的线程会严重请求锁定,因此它会干扰工具箱的线程.
如果你愿意,你可以避免使用睡眠技巧.在Ruby 1.9中,您可以使用Fiber,Revactor或EventMachine.据oldmoe说,纤维似乎很快.
如果可以使用IO.pipe,也可以保留Ruby线程.这就是在ruby 1.9.3 中实现并行测试的方式.这似乎是解决Ruby线程和GIL限制的好方法.
文档显示了示例用法:
rd, wr = IO.pipe
if fork
wr.close
puts "Parent got: <#{rd.read}>"
rd.close
Process.wait
else
rd.close
puts "Sending message to parent"
wr.write "Hi Dad"
wr.close
end
Run Code Online (Sandbox Code Playgroud)
该fork呼叫启动两个进程.在里面if,你在父进程中.在里面else,你是在孩子.Process.wait关闭子进程的调用.例如,您可以尝试在主gui循环中读取您的孩子,并且只有在您收到所有数据后才关闭并等待孩子.
编辑:如果您选择在Windows下使用fork(),则需要win32-process.
| 归档时间: |
|
| 查看次数: |
2091 次 |
| 最近记录: |