Python threading.thread.start() 不返回控制给主线程
我正在尝试写一个程序,让用户可以随时停止某段代码的执行,而不影响主程序的运行。我想用 threading.Thread 来实现这个功能,但在 Python 3.3 的 IDLE 中运行了以下代码:
from threading import *
import math
def f():
eval("math.factorial(1000000000)")
t = Thread(target = f)
t.start()
最后一行没有返回结果,最后我只好重启了 shell。这是因为全局解释器锁(Global Interpreter Lock)的问题吗,还是我做错了什么?我在 threading 的文档中没有找到与这个问题相关的内容(http://docs.python.org/3/library/threading.html)
我尝试用进程来做同样的事情:
from multiprocessing import *
import math
def f():
eval("math.factorial(1000000000)")
p = Process(target = f)
p.start()
p.is_alive()
最后一行返回了 False,尽管我在启动进程后仅仅过了几秒钟!根据我的处理器使用情况,我不得不得出结论,进程根本没有启动。有人能解释一下我哪里做错了吗?
1 个回答
Thread.start() 这个方法永远不会返回!这可能和数学库的C语言实现有关吗?
正如@eryksun在评论中提到的:math.factorial() 是用C语言实现的,它不会释放全局解释器锁(GIL),所以在它返回之前,其他的Python代码是无法运行的。
注意:multiprocessing
版本应该可以正常工作:每个Python进程都有自己的GIL。
factorial(1000000000)
的结果有几亿位数字。可以尝试用import time; time.sleep(10)
来做一个简单的计算替代。
如果你在IDLE中遇到多线程代码的问题,可以尝试在命令行中运行相同的代码,以确保错误依然存在。
如果在调用p.start()
后,p.is_alive()
返回False
,那么可能意味着f()
函数中出现了错误,比如MemoryError
。
在我的机器上,如果我把你问题中的代码粘贴到Python解释器中,p.is_alive()
会返回True
,并且其中一个CPU的使用率会达到100%。
无关紧要的提示:去掉像from multiprocessing import *
这样的通配符导入。这可能会遮蔽你代码中的其他名称,让你无法确定某个名称的具体含义,比如threading
可能会定义一个eval
函数(虽然实际上没有,但有可能),这会导致你的代码在不知不觉中出错。
我希望我的程序能够优雅地处理用户输入的各种奇怪数据。
如果你直接把用户输入传给eval()
,那么用户可以做任何事情。
有没有办法让一个进程打印,比如说,错误信息,而不需要构建管道或其他类似的结构?
这是一段普通的Python代码:
print(message) # works
不同之处在于,如果多个进程同时运行print()
,那么输出可能会混乱。你可以使用锁来同步print()
的调用。