多处理为每个进程更改当前文件夹

时间:2015-06-24 08:12:03

标签: python multithreading multiprocessing

我正在尝试使用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在某种程度上是相似的,但该解决方案并不能保证每个函数调用都发生在不同的文件夹上,这确实是我的目标。

1 个答案:

答案 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())