使用python3进行多处理只运行一次

时间:2013-08-21 00:26:34

标签: python sqlite python-3.x queue multiprocessing

我在python3中运行多个进程时遇到问题。

我的程序执行以下操作:     1.从sqllite数据库中获取条目并将它们传递给input_queue     2.创建多个进程,将项目从input_queue中取出,通过函数运行它并将结果输出到输出队列。     3.创建一个线程,从output_queue中取出项目并打印它们(这个线程显然是在前两个步骤之前启动的)

我的问题是,目前步骤2中的'功能'只运行设置的进程数,所以例如,如果将进程数设置为8,它只运行8次然后停止。我假设它会继续运行,直到它从input_queue中取出所有项目。

我是否需要重写将数据库中的条目(步骤1)带入另一个进程的函数,然后将其输出队列作为步骤2的输入队列传递?

编辑: 以下是代码的示例,我使用数字列表作为数据库条目的替代,因为它仍然以相同的方式执行。我在列表中有300个项目,我希望它能处理所有300个项目,但目前它只处理10个(我已分配的进程数)

#!/usr/bin/python3
from multiprocessing import Process,Queue
import multiprocessing
from threading import Thread


## This is the class that would be passed to the multi_processing function
class Processor:
    def __init__(self,out_queue):
        self.out_queue = out_queue
    def __call__(self,in_queue):
        data_entry = in_queue.get()
        result = data_entry*2
        self.out_queue.put(result)



#Performs the multiprocessing
def perform_distributed_processing(dbList,threads,processor_factory,output_queue):
    input_queue = Queue()


    # Create the Data processors.
    for i in range(threads):
        processor  = processor_factory(output_queue)
        data_proc = Process(target = processor,
                            args   = (input_queue,))

        data_proc.start()

    # Push entries to the queue.

    for entry in dbList:
        input_queue.put(entry)


    # Push stop markers to the queue, one for each thread.

    for i in range(threads):
        input_queue.put(None)

    data_proc.join()
    output_queue.put(None)


if __name__ == '__main__':
    output_results   = Queue()

    def output_results_reader(queue):
        while True:
            item = queue.get()
            if item is None:
                break
            print(item)


    # Establish results collecting thread.
    results_process = Thread(target = output_results_reader,args   = (output_results,))
    results_process.start()

    # Use this as a substitute for the database in the example
    dbList = [i for i in range(300)]

    # Perform multi processing
    perform_distributed_processing(dbList,10,Processor,output_results)

    # Wait for it all to finish.
    results_process.join()

2 个答案:

答案 0 :(得分:2)

不要再尝试重写整个多处理库。我认为您可以根据需要使用任何multiprocessing.Pool方法 - 如果这是一个批处理作业,您甚至可以使用同步multiprocessing.Pool.map() - 只需要编写一个生成器,而不是推送到输入队列产生线程的输入。

答案 1 :(得分:2)

为输入队列提供服务并写入输出队列的进程集合几乎就是进程池的定义。

如果你想知道如何从头开始构建一个,最好的学习方法是查看source code for multiprocessing.Pool,这非常简单的Python,而且编写得非常好。但是,正如您所料,您可以使用 multiprocessing.Pool而不是重新实现它。文档中的示例非常好。

但实际上,您可以使用executor而不是池来使这更简单。很难解释差异(再次,阅读两个模块的文档),但基本上,future是一个“智能”结果对象,这意味着代替具有各种不同方式来运行作业的池得到结果,你只需要一个愚蠢的东西,不知道如何做任何事情,但返回未来。 (当然,在最琐碎的情况下,代码看起来几乎完全相同......)

from concurrent.futures import ProcessPoolExecutor

def Processor(data_entry):
    return data_entry*2

def perform_distributed_processing(dbList, threads, processor_factory):
    with ProcessPoolExecutor(processes=threads) as executor:
        yield from executor.map(processor_factory, dbList)

if __name__ == '__main__':
    # Use this as a substitute for the database in the example
    dbList = [i for i in range(300)]
    for result in perform_distributed_processing(dbList, 8, Processor):
        print(result)

或者,如果你想要处理它们而不是按顺序处理它们:

def perform_distributed_processing(dbList, threads, processor_factory):
    with ProcessPoolExecutor(processes=threads) as executor:
        fs = (executor.submit(processor_factory, db) for db in dbList)
        yield from map(Future.result, as_completed(fs))

请注意,我还替换了进程中的队列和线程,因为它没有做任何事情,只提供交错“等待下一个结果”和“处理最新结果”的方法,并{{1} (或yield,在这种情况下)没有所有复杂性,开销和错误的可能性。