python - multiprocessing_generator 模块触发权限错误
问题描述
我找到了模块multiprocessing_generator。我使用以下代码尝试了该模块:
from multiprocessing_generator import ParallelGenerator
def my_generator():
yield (x*x for x in range(200))
with ParallelGenerator(my_generator(), max_lookahead=100) as g:
for elem in g:
print(elem)
这是我得到的错误(我在控制台中运行了我的代码,python 文件在我的桌面上):
C:\Users\crd\Desktop>python test.py Traceback(最近一次调用最后):文件“test.py”,第 69 行,与 ParallelGenerator(my_generator(), max_lookahead=100) 为 g:文件“C: \Users\crd\AppData\Local\Programs\Python\Python37-32\lib\site-packages\multiprocessing_generator__init__.py",第 62 行,输入 self.process.start() 文件“C:\Users\crd\AppData\Local\Programs\Python\Python37-32\lib\multiprocessing\process.py”,第 112 行,在 start self._popen = self._Popen( self) 文件“C:\Users\crd\AppData\Local\Programs\Python\Python37-32\lib\multiprocessing\context.py”,第 223 行,在 _Popen 返回 _default_context.get_context().Process._Popen(process_obj)文件“C:\Users\crd\AppData\Local\Programs\Python\Python37-32\lib\multiprocessing\context.py”,第 322 行,_Popen return Popen(process_obj) 文件“C:\Users\crd\AppData \Local\Programs\Python\Python37-32\lib\multiprocessing\popen_spawn_win32.py",第 65 行,在init reduction.dump(process_obj, to_child) 文件“C:\Users\crd\AppData\Local\Programs\Python\Python37-32\lib\multiprocessing\reduction.py”,第 60 行,在转储 ForkingPickler(文件,协议)中。转储(obj)AttributeError:无法腌制本地对象'ParallelGenerator。初始化..wrapped'
C:\Users\crd\Desktop>Traceback(最近一次调用最后):文件“”,第 1 行,在文件“C:\Users\crd\AppData\Local\Programs\Python\Python37-32\lib\multiprocessing\ spawn.py”,第 99 行,在 spawn_main new_handle = reduction.steal_handle(parent_pid, pipe_handle) 文件“C:\Users\crd\AppData\Local\Programs\Python\Python37-32\lib\multiprocessing\reduction.py”中,第 87 行,steal_handle _winapi.DUPLICATE_SAME_ACCESS | _winapi.DUPLICATE_CLOSE_SOURCE) PermissionError: [WinError 5] Accès refusé
我从 multiprocessing_generator 模块中清理了代码(我删除了每个尝试/异常,我将上下文管理器转换为基本函数)。但是使用下面的代码我得到了同样的错误:
from queue import Empty
from multiprocessing import Process, Queue
def ParallelGeneratorLight():
queue = Queue()
def wrapped():
for item in (x*x for x in range(200)):
queue.put(item)
process = Process(target=wrapped)
process.start()
queue.get()
print(ParallelGeneratorLight())
那有什么问题?
解决方案
multiprocessing_generator
依赖于使用'fork'
start 方法的多处理模块,因为它假定wrapped
嵌套函数(在ParallelGenerator
's中定义__init__
)可以作为target
对象传递multiprocessing.Process
。在基于fork
ing 的平台上,这很好;子进程继承父进程的完整状态(有一些小的例外,如线程),因此它对wrapped
嵌套函数具有平等的访问权限(毕竟它继承了一个精确的副本)。
问题是,在 Windows 上,唯一可用的 start 方法是'spawn'
,它要求target
(和所有参数)pickle
能够(它pickle
是它们,通过 IPC 将它们发送给孩子,并在那里重建它们),并且嵌套函数永远pickle
不能(pickle
ing 一个函数涉及将其限定名称酸洗以在另一侧导入和使用,并且嵌套函数的限定名称涉及不可导入的组件,在这种情况下,pickle
ingParallelGenerator.__init__.<locals>.wrapped
失败,因为<locals>
显然不是可导入的名称)。
基本上,multiprocessing_generator
仅适用于类 UNIX 系统,并且仅当您使用默认启动方法 ( 'fork'
) 时;如果您使用其他值(或)调用set_start_method
,则无法正常工作。'forkserver'
'spawn'
multiprocessing_generator
虽然这是一个错误,但在大多数情况下它并不是一个特别严重的错误;如果生成器必须将其值腌制,则模块几乎没有什么好处,因为大多数此类生成器要么pickle
不能自己(例如大多数类似文件的对象),要么pickle
涉及运行它们直到完成(在这种情况下,您已经失去了所有的并行性)。
抱歉,这里的简单答案是:不要multiprocessing_generator
在 Windows 上使用。
也就是说,如果您的生成器是 I/O 绑定的,您可能可以通过导入模块从模块中受益,然后立即对其进行猴子修补,以将multiprocessing
其依赖的所有组件替换为其等效multiprocessing.dummy
名称(由线程支持,并且不要依赖酸洗),例如
from multiprocessing_generator import ParallelGenerator
import multiprocessing.dummy, multiprocessing_generator
# Monkey-patch to use threads
multiprocessing_generator.Process = multiprocessing.dummy.Process
multiprocessing_generator.Queue = multiprocessing.dummy.Queue
需要明确的是,我没有对此进行测试;没有任何明示或暗示的保证,这是否会起作用。如果生成器受 CPU 限制,至少在 CPython 参考解释器上,这也是完全没有意义的,因为受 CPU 限制的生成器将在运行时持有GIL,从而阻止主线程执行工作,因此您不妨直接迭代.
推荐阅读
- jenkins-pipeline - 如何引用groovy管道脚本中的参数?
- python - 如何按功能将多列添加到数据框
- android - 如何在 EditText 上使用 android:inputType 来指定我的自定义 IME?
- java - 如何使用eclipse在java中添加firebase依赖项
- uwp - 确定 UWP 中的 Windows 10 选择了哪种资源文化回退
- python - 如何使用 pandas 替换单个值中的多个字符?
- swift - 如果您注销,如何确保注销的用户在其他用户注册时不会产生 nil uid?
- java - 如何在Java中将拆分字符串存储为数组?
- typescript - 如何将嵌套的 for 循环变量从一个函数传递到另一个函数?
- java - 我如何知道 2 个引用是否指向同一个对象?