这可能是我很遗憾的事情。
为什么我不能使用pool.map(sys.stdout.write, iterable)
?
我可以使用相同的可迭代来使用pool.map(len, iterable)
,但在使用sys.stdout.write
时,我会遇到以下异常:
TypeError: expected string or Unicode object, NoneType found
这是追踪:
Traceback (most recent call last):
File "/home/reut/python/print_mult.py", line 19, in <module>
pool.map(sys.stdout.write, messages)
File "/usr/lib/python2.7/multiprocessing/pool.py", line 251, in map
return self.map_async(func, iterable, chunksize).get()
File "/usr/lib/python2.7/multiprocessing/pool.py", line 558, in get
raise self._value
TypeError: expected string or Unicode object, NoneType found
#!/usr/bin/env python
import multiprocessing
import sys
# pool of 10 workers
pool = multiprocessing.Pool(10)
messages = ["message #%d\n" % i for i in range(100)]
print messages
pool.map(sys.stdout.write, messages) # doesn't work - error
# print pool.map(len, messages) # works
当我使用ThreadPool
(来自multiprocessing.pool
)时,它有效,所以我认为它与无法跨进程共享sys.stdout
流有关。
from multiprocessing import Process
import sys
# pool of 10 workers
processes = []
for i in range(10):
processes.append(Process(target=sys.stdout.write, args=("I am process %d" % i, )))
for p in processes:
p.start()
for p in processes:
p.join()
所以现在我感到困惑,因为我知道常规流程和地图流程之间的差异就是它所要求的。我不确定这里的相关性如何。我唯一能想到的是,map在内部存储了target
,并且无法像Process
的手动构造函数那样与工作者共享它。
答案 0 :(得分:3)
真正的错误是隐藏的。您只能传递一个可直接从模块名称空间引用的函数。但是,在某些情况下,有办法解决这个限制。 Unix有一个特殊的功能,可以分叉进程并复制其所有内存。这就是实例方法可以“传递”到子进程的方式 - 实际上没有传递任何东西。在Windows平台上,无法分叉进程,但必须生成进程。这意味着启动了一个新的解释器。为了让解释器运行给定的函数,它会发送要运行的函数的名称和它所在的模块。解释器在最终运行函数之前导入模块并查找函数。
对于属于池的进程,该进程已经启动,因此无法从分叉接收要运行的相应函数/方法的副本中受益。相反,它必须使用与生成新进程时相同的技术。这就是为什么你可以让你的第二次编辑工作,但不能让你的工作池。
解决问题的最简单方法是使print成为函数而不是语句。
from __future__ import print_function
import multiprocessing
import sys
if __name__ == '__main__':
pool = multiprocessing.Pool(2)
messages = ["message #%d\n" % i for i in range(5)]
print(messages) # <- notice the brackets around the arguments to print
pool.map(print, messages)
如果没有你可以定义一个能为你打印的功能,并将其用作地图的功能。
import multiprocessing
import sys
def stdout_write(arg):
sys.stdout.write(arg)
def stdout_print(arg):
print arg
if __name__ == '__main__':
pool = multiprocessing.Pool(2)
messages = ["message #%d\n" % i for i in range(5)]
print messages
pool.map(stdout_print, messages)
答案 1 :(得分:2)
我确实不确定原因,但是pool.map()
要求函数返回一个字符串。
对程序的这种简单更改可以正确运行。
#!/usr/bin/env python
import multiprocessing
import sys
def prn(s):
sys.stdout.write(s)
return ''
# pool of 10 workers
pool = multiprocessing.Pool(10)
messages = ["message #%d\n" % i for i in range(100)]
print messages
pool.map(prn, messages) # doesn't work - error
# print pool.map(len, messages) # works
我检查了文档,但我没有看到这个要求,所以我不知道为什么要强制执行。