使用Python pool.map让多个进程对列表执行操作

3

我试图启动6个线程,每个线程从文件列表中取一个项目,删除它,然后打印该值。

from multiprocessing import Pool

files = ['a','b','c','d','e','f']

def convert(file):
    process_file = files.pop()
    print process_file

if __name__ == '__main__':

    pool = Pool(processes=6)
    pool.map(convert,range(6))

预期输出应该是:
a
b
c
d
e
f

相反,输出结果为:

f
f
f
f
f
f

发生了什么?提前感谢。

2个回答

5

问题的一部分在于你没有处理池的多进程性质。(需要注意的是,在Python中,由于全局解释器锁,多线程并不能提高性能)。

你是否有修改原始列表的原因?你目前的代码没有使用传入的可迭代对象,而是编辑了一个共享的可变对象,在并发世界中这是危险的。一个简单的解决方案如下:

from multiprocessing import Pool

files = ['a','b','c','d','e','f']

def convert(aFile):
    print aFile

if __name__ == '__main__':

    pool = Pool() #note the default will use the optimal number of workers
    pool.map(convert,files)

您的问题让我深思,因此我进行了更多探索,以了解Python为什么会以这种方式运行。看起来Python正在进行一些有趣的黑魔法,并将对象深度复制(同时保持id不变,这是非标准的)到新进程中。通过改变使用的进程数量,可以看到这一点:

from multiprocessing import Pool

files = ['d','e','f','a','b','c',]

a = sorted(files)
def convert(_):
    print a == files
    files.sort()
    #print id(files) #note this is the same for every process, which is interesting

if __name__ == '__main__':

    pool = Pool(processes=1) #
    pool.map(convert,range(6))

==> 除了第一次调用之外,所有调用都按预期打印“True”。

如果将进程数设置为2,则它的确定性较低,因为它取决于哪个进程实际上首先执行其语句。


这正是我一直在寻找的。感谢您帮助我理解Pool.map函数。 - ensnare

2

一个解决方案是使用multiprocessing.dummy,它使用线程而不是进程。只需将您的导入更改为:

from multiprocessing.dummy import Pool

“解决”了问题,但不能保护共享内存免受并发访问。您仍应使用线程锁队列putget配合使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接