Python3 Process.join() 在多线程中创建进程时实际上并没有在 Linux 上等待



我需要在线程中创建的进程上超时,但是我遇到了一个奇怪的行为,我不确定如何继续。

以下在Linux 上执行的代码产生了一个奇怪的错误(如果thrads 的数量大于 2(我的笔记本电脑有 8 核)或代码在循环中执行了几次)process.join() 实际上并没有等待进程完成或超时到期,而只是继续下一条指令。

如果在带有python3.9Windows上执行相同的代码,则会无缘无故地在库中给出循环导入错误

如果它用python 3.8执行,它几乎可以完美地工作,直到像256个线程,然后在process.join()上给出与linux相同的stange beahvour。

Windows Python 3.9 上的错误:ImportError: cannot import name 'Queue' from partially initialized module 'multiprocessing.queues' (most likely due to a circular import)

此外,如果我从进程中删除返回值,那么我就会删除队列。在linux上,process.join() 开始在任意大的n_threads正常工作。但是,即使在非常小的n_threads中,在循环中运行代码也会出错

import random
from multiprocessing import Process, Queue
from threading import Thread
def dummy_process():
return random.randint(1, 10)
#function to retrieve process return value
def process_returner(queue, function, args):
queue.put(function(*args))
#function that creates the process with timeout
def execute_with_timeout(function, args, timeout=3):

q = Queue()
p1 = Process(
target=process_returner,
args=(q, function, args),
name="P",
)
p1.start()
p1.join(timeout=timeout) # SOMETIME IT DOES NOT WAIT FOR THE PROCESS TO FINISH
if p1.exitcode is None:
print(f"Oops, {p1} timeouts!")# SO IT RAISES THIS ERROR even if nowhere near 3 secods have passed
raise TimeoutError
p1.terminate()
return q.get() if not q.empty() else None

#thread that just call the new process and stores the return value in the given array
def dummy_thread(result_array, index):
try:
result_array[index] = execute_with_timeout(dummy_process, args=())
except TimeoutError:
pass

def test():
#in loop because with low n_threads as 4 the error is not so common
for _ in range(10):
n_threads =8
results = [-1] * n_threads
threads = set()
for i in range(n_threads):
t = Thread(target=dummy_thread, args=(results, i))
threads.add(t)
t.start()
for t in threads:
t.join()
print(results)

if __name__ == '__main__':
test()

我在 Linux 上使用multiprocessing模块时遇到了类似的问题。Process.join()立即开始返回,而不是等待。exitcode等于Noneis_alive()将返回True

事实证明,问题不在于Python代码。我从一个有时会执行trap "" SIGCHLD的 Bash 脚本调用我的 Python 程序。通常,设置trap只影响脚本本身,但trap "" some_signal告诉 shell 的子进程也忽略信号。阻塞SIGCHLD会干扰multiprocessing模块。

就我而言,在 Python 程序的开头添加signal.signal(signal.SIGCHLD, signal.SIG_DFL)解决了这个问题。

最新更新