使用具有最大同时进程数的multiprocessing.Process

时间:2014-01-02 15:51:38

标签: python multithreading multiprocessing

我有Python代码:

from multiprocessing import Process

def f(name):
    print 'hello', name

if __name__ == '__main__':
    for i in range(0, MAX_PROCESSES):
        p = Process(target=f, args=(i,))
        p.start()

运行良好。但是,MAX_PROCESSES是可变的,可以是1512之间的任何值。由于我只在具有8核心的计算机上运行此代码,因此我需要确定是否可以限制允许同时运行的进程数。我调查了multiprocessing.Queue,但它看起来并不像我需要的那样 - 或许我正在错误地解释文档。

有没有办法限制同时multiprocessing.Process的同时运行?

3 个答案:

答案 0 :(得分:76)

使用multiprocessing.Pool最合理的做法是根据系统上可用的最大内核数量生成一个工作进程池,然后在内核可用时基本上提供任务。

标准文档(http://docs.python.org/2/library/multiprocessing.html#using-a-pool-of-workers)中的示例显示您还可以手动设置核心数量:

from multiprocessing import Pool

def f(x):
    return x*x

if __name__ == '__main__':
    pool = Pool(processes=4)              # start 4 worker processes
    result = pool.apply_async(f, [10])    # evaluate "f(10)" asynchronously
    print result.get(timeout=1)           # prints "100" unless your computer is *very* slow
    print pool.map(f, range(10))          # prints "[0, 1, 4,..., 81]"

如果您的代码需要,还可以通过multiprocessing.cpu_count()方法计算给定系统上的核心数量,这也很方便。

编辑:这里有一些似乎适合您特定案例的草案代码:

import multiprocessing

def f(name):
    print 'hello', name

if __name__ == '__main__':
    pool = multiprocessing.Pool() #use all available cores, otherwise specify the number you want as an argument
    for i in xrange(0, 512):
        pool.apply_async(f, args=(i,))
    pool.close()
    pool.join()

答案 1 :(得分:2)

更一般而言,它也可能像这样:

import multiprocessing
def chunks(l, n):
    for i in range(0, len(l), n):
        yield l[i:i + n]

numberOfThreads = 4


if __name__ == '__main__':
    jobs = []
    for i, param in enumerate(params):
        p = multiprocessing.Process(target=f, args=(i,param))
        jobs.append(p)
    for i in chunks(jobs,numberOfThreads):
        for j in i:
            j.start()
        for j in i:
            j.join()

当然,这种方式非常残酷(因为它等待垃圾中的每个进程,直到它继续下一个块为止)。仍然可以在大约相等的函数调用运行时间上很好地工作。

答案 2 :(得分:2)

我认为Semaphore是您要寻找的东西,它计数到0后将阻塞主进程。示例代码:

from multiprocessing import Semaphore

def f(name, sema):
    print 'hello', name
    sema.release()

if __name__ == '__main__':
    concurrency = 20
    total_task_num = 1000
    sema = Semaphore(concurrency)
    all_processes = []
    for i in range(total_task_num):
        # once `concurrency` processes are running, 
        # the following code will block main process
        sema.acquire()
        p = Process(target=f, args=(i, sema))
        all_processes.append(p)
        p.start()

    # inside main process, wait for all processes to finish
    for p in all_processes:
        p.join()

另一种方法可能会使代码看起来更加结构化,但是如果total_task_num非常大,则会消耗过多的资源,如下所示:

from multiprocessing import Semaphore

def f(name, sema):
    sema.acquire()
    print 'hello', name
    sema.release()

if __name__ == '__main__':
    concurrency = 20
    total_task_num = 1000
    sema = Semaphore(concurrency)
    all_processes = []
    for i in range(total_task_num):
        p = Process(target=f, args=(i, sema))
        all_processes.append(p)
        p.start()

    # inside main process, wait for all processes to finish
    for p in all_processes:
        p.join()

以上代码将创建total_task_num个进程,但只有concurrency个进程将在其他进程被阻止时运行。