在以下代码中:

import threading

def infinite_loop():
    while True:
        pass

def huge_sum():
    return sum(range(2**100))

thread = threading.Thread(target=huge_sum)
thread.start()
thread.join(1)

print("Done")

我希望脚本在一秒后打印"Done",因为join()将超时,但脚本却挂起.如果您将对huge_sum的呼叫替换为infinite_loop,则可以正常工作.问题似乎出在内置的sum()功能上.

有没有一种方法可以可靠地获得类似join()的超时行为no matter what the thread is doing?我不介意古怪的元编程解决方案,这是一个非常小众的应用程序.然而,在大多数情况下,我不能修改在线程内执行的代码(例如,"使用循环而不是sum"不是一个解决方案).

Linux、Python3.8.

推荐答案

bltinmodule.cintfloat中的builtin_sum_impl被优化为在不释放全局解释程序锁(GIL)的情况下执行求和.Python一次只允许在单个线程中执行字节代码.字节码执行器经常会释放GIL,以便其他线程可以运行.

C代码可以释放GIL,让Python级别的代码并行运行.但sum不能做到这一点.它在对int求和时保持GIL,这样它就不必担心其他线程在进行求和时更改被求和的对象.这也意味着,在完成之前,任何Python代码都不能在任何线程中运行.

一种 Select 是在不同的过程中完成这项工作.对于像Linux这样的Forking 操作系统,您可以使用单独的进程进行求和.子元素可以读取父内存,因此即使内存中有一个很大的列表,它也可以工作.这增加了创建子进程的开销,因此不是免费的.

如果你能在子进程中生成数据,那就更好了,尤其是当你想并行地做多个求和的时候.在你的range个例子中,你就会这么做.

或者,如果您有一大组整数要处理,您可以转移到NumPy数组,其中的一些运算,如array.sum,将释放GIL.它在您的示例中不起作用,因为range(2**100)太大了.但我想这只是一个例子.

您可以将其扩展到并行运行的多个进程,也许可以使用multiprocessing.Pool个进程.做到这一点的最佳方式取决于几个因素.例如,如果父对象中有大量数据,则不希望将其作为.map()(或其他池方法)中的参数传递,因为Python必须将参数复制到Worker.相反,您可以使用工作人员恰好知道的某个全局变量.

Python相关问答推荐

为什么Pydantic在我申报邮箱时说邮箱丢失

Python在通过Inbox调用时给出不同的响应

自动编码器和极坐标

当pip为学校作业(job)安装sourcefender时,我没有收到匹配的分发错误.我已经try 过Python 3.8.10和3.10.11

在Docker中运行HAProxy时无法获得503服务

Docker-compose:为不同项目创建相同的容器

在两极中实施频率编码

Ibis中是否有一个ANY或ANY_UTE表达,可以让我比较子查询返回的一组值中的值?

如何在Python中增量更新DF

Python中使用时区感知日期时间对象进行时间算术的Incredit

Python daskValue错误:无法识别的区块管理器dask -必须是以下之一:[]

如何比较numPy数组中的两个图像以获取它们不同的像素

如何检测背景有噪的图像中的正方形

如何让剧作家等待Python中出现特定cookie(然后返回它)?

对整个 pyramid 进行分组与对 pyramid 列子集进行分组

如何获取TFIDF Transformer中的值?

对所有子图应用相同的轴格式

让函数调用方程

与命令行相比,相同的Python代码在Companyter Notebook中运行速度慢20倍

从旋转的DF查询非NaN值