我正在尝试使用multiprocessing
模块并行化一些计算。
如何确保multiprocessing.Pool.map_async
生成的每个进程都在另一个(以前创建的)文件夹上运行?
问题是每个进程调用一些第三部分库,这些部分库将临时文件写入磁盘,如果你在同一个文件夹中运行其中的许多文件,那么你就会把另一个文件搞得一团糟。
此外,我无法为map_async所做的每个函数调用创建一个新文件夹,而是希望创建尽可能少的文件夹(即每个进程一个)。
代码与此类似:
import multiprocessing,os,shutil
processes=16
#starting pool
pool=multiprocessing.Pool(processes)
#The asked dark-magic here?
devshm='/dev/shm/'
#Creating as many folders as necessary
for p in range(16):
os.mkdir(devshm+str(p)+'/')
shutil.copy(some_files,p)
def example_function(i):
print os.getcwd()
return i*i
result=pool.map_async(example_function,range(1000))
因此,在任何时候,每次调用example_function都会在另一个文件夹上执行。
我知道解决方案可能是使用子进程来生成不同的进程,但我想坚持多处理(我需要为每个生成的子进程挑选一些对象,写入磁盘,读取,取消,而不是通过函数调用传递对象本身(使用functools.partial)。
PS。
This question在某种程度上是相似的,但该解决方案并不能保证每个函数调用都发生在不同的文件夹上,这确实是我的目标。
答案 0 :(得分:3)
由于您未在问题中指明,我假设您在执行完功能后不需要目录内容。
绝对最简单的方法是创建和销毁使用它们的函数中的临时目录。这样,代码的其余部分并不关心工作进程的环境/目录,并且Pool
非常适合。我还会使用python的内置功能来创建临时目录:
import multiprocessing, os, shutil, tempfile
processes=16
def example_function(i):
with tempfile.TemporaryDirectory() as path:
os.chdir(path)
print(os.getcwd())
return i*i
if __name__ == '__main__':
#starting pool
pool=multiprocessing.Pool(processes)
result=pool.map(example_function,range(1000))
注意: tempfile.TemporaryDirectory
是在python 3.2中引入的。如果您使用的是旧版本的python,则可以copy the wrapper class into your code。
如果确实需要事先设置目录......
尝试使用Pool
进行此操作有点笨拙。您可以传递要与数据一起使用的目录名称,但是您只能传递等于目录数的初始数量。然后,您需要使用类似imap_unordered
的内容来查看结果何时完成(并且它的目录可以重复使用)。
在我看来,一个更好的方法是根本不使用Pool
,而是创建单独的Process
对象并将每个对象分配到一个目录。如果你需要控制Process
环境的某些部分,这通常会更好一些,当你的问题是数据驱动并且不关心时,Pool
通常会更好流程或他们的环境。
有不同的方法向/从Process对象传递数据,但最简单的是队列:
import multiprocessing,os,shutil
processes=16
in_queue = multiprocessing.Queue()
out_queue = multiprocessing.Queue()
def example_function(path, qin, qout):
os.chdir(path)
for i in iter(qin.get, 'stop'):
print(os.getcwd())
qout.put(i*i)
devshm='/dev/shm/'
# create processes & folders
procs = []
for i in range(processes):
path = devshm+str(i)+'/'
os.mkdir(path)
#shutil.copy(some_files,path)
procs.append(multiprocessing.Process(target=example_function, args=(path,in_queue, out_queue)))
procs[-1].start()
# send input
for i in range(1000):
in_queue.put(i)
# send stop signals
for i in range(processes):
in_queue.put('stop')
# collect output
results = []
for i in range(1000):
results.append(out_queue.get())