如何在函数中使用多处理?

Jed*_*edi 2 python multiprocessing python-3.x

我想在"a.py"中定义一个函数,它使用多处理进行并行化,然后将其作为库函数导入"b.py".例如,在"a.py"中:

import multiprocessing as mp, queue

def MPWorker(input, i):
    input.put(i)


def MPTest(MaxMPNum):
    jobs = []
    BatchResult = queue.Queue()
    for i in range(MaxMPNum):
        p = mp.Process(target=MPWorker, args=(BatchResult, i + 1))
        p.start()
        print("this is", i)
        jobs.append(p)
    for i in range(MaxMPNum):
        print("getting", i)
        result = BatchResult.get()
        print(result)
Run Code Online (Sandbox Code Playgroud)

然后在"b.py"中:

import a
a.MPTest(10)
Run Code Online (Sandbox Code Playgroud)

但是,它不会工作,我总会得到错误:_pickle.PicklingError:无法pickle:_thread上的属性查找锁失败.那么,是否有可能以这种方式使用python的多处理或者我错过了什么?

整个回溯,略有编辑(Python 3.x,Windows):

Traceback (most recent call last):
  File "F:/b.py", line 72, in <module>
    a.MPTest(5)
  File "F:\a.py", line 566, in MPTest
    p.start()
  File "C:\Python34\lib\multiprocessing\process.py", line 105, in start
    self._popen = self._Popen(self)
  File "C:\Python34\lib\multiprocessing\context.py", line 212, in _Popen
    return _default_context.get_context().Process._Popen(process_obj)
  File "C:\Python34\lib\multiprocessing\context.py", line 313, in _Popen
    return Popen(process_obj)
  File "C:\Python34\lib\multiprocessing\popen_spawn_win32.py", line 66, in __init__
    reduction.dump(process_obj, to_child)
  File "C:\Python34\lib\multiprocessing\reduction.py", line 59, in dump
    ForkingPickler(file, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <class '_thread.lock'>: attribute lookup lock on _thread failed
Run Code Online (Sandbox Code Playgroud)

aba*_*ert 5

问题是你正在使用queue.Queue,它只能在同一进程中的线程之间工作,而不是multiprocessing.Queue在进程之间工作.

根据您的平台和使用方式,这将以不同的方式失败.在你的情况下,因为你试图将队列作为参数传递给Process构造函数,并且你在Windows上,你得到了最好的错误:你试图挑选队列本身,然后失败.*在Unix上,你可能实际上可以成功地将队列传递给子进程,但是当您使用它时,它可能会丢失大部分值(OS X)或死锁(大多数其他系统).

正如文档解释的那样,multiprocessing.Queue"是一个近乎克隆的queue.Queue",除了它是"线程和进程安全"而不仅仅是线程安全.


如果您认为自己使用multiprocessing.Queue,那么您的错误就在于此:

import multiprocessing as mp, queue
Run Code Online (Sandbox Code Playgroud)

这不导入multiprocessingmpqueue,它进口multiprocessingmp,进口queue的本身.有关import详细信息,请参阅参考资料

事实上这对人类来说是模棱两可的(尽管它对解析器来说并不含糊)是Python中不鼓励使用多重导入语句的原因之一.例如,PEP 8说"进口通常应该在不同的线上".


*当你腌制它时队列本身引发异常可能会更好,而不是依赖于它使用一些不可打击的线程同步对象的事实,因为酸洗a _thread.lock引起的腌制并不是很明显queue.Queue.