如何限制Python中的并发线程数?

时间:2013-08-21 00:53:16

标签: python multithreading

如何限制Python中并发线程的数量?

例如,我有一个包含许多文件的目录,我想处理所有这些文件,但是并行处理所有文件只有4个。

这是我到目前为止所做的:

def process_file(fname):
        # open file and do something                                                                                            

def process_file_thread(queue, fname):
    queue.put(process_file(fname))

def process_all_files(d):
    files=glob.glob(d + '/*')
    q=Queue.Queue()
    for fname in files:
        t=threading.Thread(target=process_file_thread, args=(q, fname))
        t.start()
    q.join()

def main():
    process_all_files('.')
    # Do something after all files have been processed

如何修改代码,以便一次只运行4个线程?

请注意,我想等待处理所有文件,然后继续处理已处理的文件。

2 个答案:

答案 0 :(得分:7)

  

例如,我有一个包含许多文件的目录,我想处理所有这些文件,但是并行处理所有文件只有4个。

这正是线程池的作用:您创建作业,并且池一次并行运行4个。您可以通过使用执行程序使事情变得更简单,您可以将其交给函数(或其他可调用函数),并将结果交给期货。你可以自己构建所有这些,但你不必。*

stdlib的concurrent.futures模块是最简单的方法。 (对于Python 3.1及更早版本,请参阅backport。)事实上,one of the main examples非常接近您想要做的事情。但是让我们根据您的具体用例进行调整:

def process_all_files(d):
    files = glob.glob(d + '/*')
    with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
        fs = [executor.submit(process_file, file) for file in files]
        concurrent.futures.wait(fs)

如果您希望process_file返回某些内容,那就差不多了:

def process_all_files(d):
    files = glob.glob(d + '/*')
    with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
        fs = [executor.submit(process_file, file) for file in files]
        for f in concurrent.futures.as_completed(fs):
            do_something(f.result())

如果你也想处理异常......好吧,看看这个例子;围绕try的来电只是except / result()


*如果您想自己构建它们,那并不难。 multiprocessing.pool的来源写得很好并且评论过,并没有那么复杂,而且大多数硬件与线程无关; concurrent.futures的来源更简单。

答案 1 :(得分:0)

我几次使用这种技术,我认为这有点难看:

import threading

def process_something():
    something = list(get_something)

    def worker():
        while something:
            obj = something.pop()
            # do something with obj

   threads = [Thread(target=worker) for i in range(4)]
   [t.start() for t in threads]
   [t.join() for t in threads]