嗨,
我偶然发现了processPoolExecutor
的一个问题,在这个问题上,进程应该不能访问数据。让我解释一下:
我有一个类似于下面示例的情况:我得到了几个运行,每个运行以不同的参数开始。他们并行计算他们的东西,没有理由相互交互。现在,正如我所理解的,当一个进程分叉时,它会复制自己。子进程与其父进程具有相同的(内存)数据,但是如果它更改任何内容,它将在自己的副本上进行更改。如果我想让更改在子进程的生命周期内继续存在,我会调用队列、管道和其他IPC东西。
from concurrent.futures import ProcessPoolExecutor
from multiprocessing import current_process, set_start_method
class Static:
integer: int = 0
def inprocess(run: int) -> None:
cp = current_process()
# Print current state
print(f"[{run:2d} {cp.pid} {cp.name}] int: {Static.integer}", flush=True)
# Check value
if Static.integer != 0:
raise Exception(f"[{run:2d} {cp.pid} {cp.name}] Variable already set!")
# Update value
Static.integer = run + 1
def pooling():
cp = current_process()
# Get master's pid
print(f"[{cp.pid} {cp.name}] Start")
with ProcessPoolExecutor(max_workers=2) as executor:
for i, _ in enumerate(executor.map(inprocess, range(4))):
print(f"run #{i} finished", flush=True)
if __name__ == '__main__':
set_start_method("fork") # enforce fork
pooling()
[1998 MainProcess] Start
[ 0 2020 Process-1] int: 0
[ 2 2020 Process-1] int: 1
[ 1 2021 Process-2] int: 0
[ 3 2021 Process-2] int: 2
run #0 finished
run #1 finished
concurrent.futures.process._RemoteTraceback:
"""
Traceback (most recent call last):
File "/usr/lib/python3.6/concurrent/futures/process.py", line 175, in _process_worker
r = call_item.fn(*call_item.args, **call_item.kwargs)
File "/usr/lib/python3.6/concurrent/futures/process.py", line 153, in _process_chunk
return [fn(*args) for args in chunk]
File "/usr/lib/python3.6/concurrent/futures/process.py", line 153, in <listcomp>
return [fn(*args) for args in chunk]
File "<stdin>", line 14, in inprocess
Exception: [ 2 2020 Process-1] Variable already set!
"""
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 29, in <module>
File "<stdin>", line 24, in pooling
File "/usr/lib/python3.6/concurrent/futures/process.py", line 366, in _chain_from_iterable_of_lists
for element in iterable:
File "/usr/lib/python3.6/concurrent/futures/_base.py", line 586, in result_iterator
yield fs.pop().result()
File "/usr/lib/python3.6/concurrent/futures/_base.py", line 425, in result
return self.__get_result()
File "/usr/lib/python3.6/concurrent/futures/_base.py", line 384, in __get_result
raise self._exception
Exception: [ 2 2020 Process-1] Variable already set!
我很感激任何帮助。
我找到了multiprocessing.pool.pool
,在这里可以设置maxtasksperchild=1
,这样工作进程的任务完成后就会被销毁。但是我不喜欢multiprocessing
接口;processPoolExecutor
使用起来更加舒适。此外,池的全部思想是节省进程设置时间,当每次运行后终止宿主进程时,这将被取消。
python中的全新进程不共享内存状态。但是processPoolExecutor
重用流程实例。它毕竟是一个活动进程池。我假设这样做是为了防止一直弯腰和启动进程的OS开销。
您可以在其他分发技术中看到相同的行为,比如celery,如果您不小心,您可能会在执行之间泄漏全局状态。
我建议您更好地管理命名空间以封装数据。例如,使用您的示例,您可以将代码和数据封装在父类中,并在inprocess()
中实例化,而不是将其存储在共享命名空间中,比如类中的静态字段或直接存储在模块中。这样,该对象最终将由垃圾回收器清理:
class State:
def __init__(self):
self.integer: int = 0
def do_stuff():
self.integer += 42
def use_global_function(state):
state.integer -= 1664
state.do_stuff()
def inprocess(run: int) -> None:
cp = current_process()
state = State()
print(f"[{run:2d} {cp.pid} {cp.name}] int: {state.integer}", flush=True)
if state.integer != 0:
raise Exception(f"[{run:2d} {cp.pid} {cp.name}] Variable already set!")
state.integer = run + 1
state.do_stuff()
use_global_function(state)
问题内容: 我正在研究模仿Paint的程序。问题是当我绘制新形状时,以前的形状会被删除。我试图注释掉我的paintComponents的超级调用,该调用可以工作,但是留下了太多的绘图。 问题答案: 正如您所发现的,您需要调用,否则背景不会被绘制,并且一切都是一团糟。问题在于,由于该字段只能是单个值,因此一次只能绘制一个形状。一种解决方案是创建一个形状,然后在in中绘制每个形状。
问题内容: 我正在编写一个程序,它将监视特定目录中包含下载URL的新文件。一旦检测到新文件,它将在父级继续监视目录的同时创建一个新过程来进行实际下载。我正在使用来自的界面。我的问题是,除非我调用process.join(),否则子进程仍在运行,但是process.join()是一个阻止函数,无法实现创建子进程来处理实际下载的目的。 我的问题是,是否有一种以非阻塞方式加入子进程的方法,该方法将允许父
问题内容: 在Java中,为什么以下代码行不起作用? 如果我将其更改为 起初,我以为您可能没有接口列表,但是我可以创建一个很好的接口。 有想法吗? 问题答案: 泛型类型比较古怪。 表示或任何子类型,但仅表示。如果您想要一个子类型,您需要 我怀疑你可以用 无法执行此操作的原因是,您可以使用对引用的引用,并且必须谨慎使用额外的间接级别。 使用泛型,您可以有两个间接级别,这会给您带来问题,因此它们更容易
问题内容: 以下内容无法编译,并给出“非法前向引用”消息: 但是,以下内容会编译: 但是以下内容无法编译,并给出“非法前向引用”消息: 为什么InstanceInitialisation1不能编译StaticInitialisation和InstanceInitialisation2? 问题答案: JLS的第8.3.3节涵盖了这一点: 有时会限制使用其声明在文本后出现的类变量,即使这些类变量在范围
我得到的错误是:在Python 3中没有名为“Tkinter”的模块。我正在尝试运行这段代码。
我有一个应用程序,它的工作是启动和停止各种其他进程。 问题在于Qt应用程序不会完全停止。Qt 窗口关闭,但进程仍在后台运行,直到调用 TerminateProcess(), 然后 Qt 应用程序退出而不清理。 我正在使用微软概述的这种方法。甚至Qt源代码也使用这种方法来终止进程,除了他们也向主线程发布WM_CLOSE。我也已经将其添加到我的应用程序中,但它仍然只是关闭窗口,离开进程。 我发现有趣的