Python threading.thread.start() 不会将控制权返回给主线程

Posted

技术标签:

【中文标题】Python threading.thread.start() 不会将控制权返回给主线程【英文标题】:Python threading.thread.start() doesn't return control to main thread 【发布时间】:2014-04-03 23:52:57 【问题描述】:

我正在尝试一个程序以这样一种方式执行一段代码,即用户可以随时停止其执行而无需停止主程序。我以为我可以使用 threading.Thread 来做到这一点,但后来我在 IDLE (Python 3.3) 中运行了以下代码:

from threading import *
import math
def f():
    eval("math.factorial(1000000000)")
t = Thread(target = f)
t.start()

最后一行没有返回:我最终重新启动了 shell。这是全局解释器锁的结果,还是我做错了什么?我在线程文档 (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() is implemented as a C function 不会发布 GIL,因此在返回之前不会运行其他 Python 代码。

注意:multiprocessing 版本应该按原样工作:每个 Python 进程都有自己的 GIL。


factorial(1000000000) 有数亿位数。改用import time; time.sleep(10) 作为虚拟计算。

如果您在 IDLE 中遇到多线程代码问题,请从命令行尝试相同的代码,以确保错误仍然存​​在。

如果p.is_alive()p.start() 已被调用后返回False,则可能意味着f() 函数中存在错误,例如MemoryError

在我的机器上,p.is_alive() 返回True,如果我将问题中的代码粘贴到 Python shell 中,其中一个 cpus 为 100%。

不相关:删除通配符导入,例如 from multiprocessing import *。它们可能会隐藏代码中的其他名称,因此您无法确定给定名称的含义例如,threading 可以定义 eval 函数(它没有但它可以)具有相似但不同的语义可能会破坏你的代码静默。

我希望我的程序能够优雅地处理来自用户的荒谬输入

如果您将用户输入直接传递给eval(),那么用户可以执行任何操作

有没有什么方法可以让进程在不构造管道或其他类似结构的情况下打印错误消息?

是一段普通的Python代码:

print(message) # works

不同之处在于,如果多个进程运行print(),则输出可能会出现乱码。您可以使用锁来同步print() 调用。

【讨论】:

您对 time.sleep() 的建议如我所料返回。但是,我选择了像 factorial(1000000000) 这样的荒谬计算,因为我希望我的程序能够优雅地处理来自用户的荒谬输入。此代码在 shell 中的执行方式完全相同。有没有什么方法可以在不构造管道或其他类似结构的情况下打印错误消息? @user3372045:我已经从评论中回答了你的问题。您的多处理代码也可以按预期在我的机器上运行 (p.is_alive() is True) 我不确定您所说的“用户可以做任何事情”是什么意思。我的计划是在单独的控制线程中处理 eval() 语句,如果那里出现问题,主线程不会受到伤害。如果 Thread.start() 永远不会返回,这将不起作用!这可能与数学库的 C 实现有关吗?如果是这样,我可以在纯 Python 中重写像阶乘这样的操作。慢得多,但如果我可以中断操作,那么值得。

以上是关于Python threading.thread.start() 不会将控制权返回给主线程的主要内容,如果未能解决你的问题,请参考以下文章

Python代写,Python作业代写,代写Python,代做Python

Python开发

Python,python,python

Python 介绍

Python学习之认识python

python初识