苦苦于多处理队列

时间:2018-01-05 12:45:38

标签: python python-3.x parallel-processing multiprocessing

我的结构(大规模简化)如下所示:

import multiprocessing

def creator():
    # creates files
    return


def relocator():
    # moves created files
    return


create = multiprocessing.Process(target=creator)
relocate = multiprocessing.Process(target=relocator)
create.start()
relocate.start()

我要做的是,creator创建的一堆文件一旦创建,就会被relocator移动到另一个目录。< / p>

我想在这里使用multiprocessing的原因是:

  • 我不希望creator等待移动首先完成,因为移动需要时间我不想浪费。
  • 在开始复制之前首先创建所有文件不是一个选项,因为驱动器中没有足够的空间用于所有文件。

我希望creatorrelocator进程都是串行的(每次一个文件)但是并行运行。行动的“日志”应该像这样:

# creating file 1
# creating file 2 and relocating file 1
# creating file 3 and relocating file 2
# ...
# relocating last file

根据我所读到的内容,Queue是前往此处的方式。

策略(也许不是最好的?!)

创建文件后,它将进入队列,在完成重定位后,它将从队列中删除。

然而,我遇到了编码问题;同时创建多个文件(并行运行creator的多个实例)和其他...

我会非常感谢任何想法,提示,解释等

1 个答案:

答案 0 :(得分:1)

让我们把你的想法分解为这个功能:

  1. 创作者应该创建文件(例如100个)

  2. 重定位器应一次移动1个文件,直到没有其他文件可以移动

  3. 创作者可以在 Relocator 之前结束,所以它也可以     把自己变成一个 Relocator 两者都要知道什么时候去     完成

  4. 因此,我们有两个主要功能:

    def create(i):
        # creates files and return outpath
        return os.path.join("some/path/based/on/stuff", "{}.ext".format(i))
    
    
    def relocate(from, to):
        # moves created files
        shuttil.move(from, to)
    

    现在让我们创建我们的流程:

    from multiprocessing import Process, Queue
    
    comm_queue = Queue()
    
    #process that create the files and push the data into the queue
    def creator(comm_q):
        for i in range(100):
            comm_q.put(create(i))
        comm_q.put("STOP_FLAG") # we tell the workers when to stop, we just push one since we only have one more worker
    
    #the relocator works till it gets an stop flag
    def relocator(comm_q):
        data = comm_q.get()
        while data != "STOP_FLAG":
            if data:
                relocate(data, to_path_you_may_want)
            data = comm_q.get()
    
    creator_process= multiprocessing.Process(target=creator, args=(comm_queue))
    relocators = multiprocessing.Process(target=relocator, args=(comm_queue))
    creator_process.start()
    relocators .start()
    

    这样我们现在就拥有了一个创建者和一个重定位器,但是,现在我们要让 Creator 在创建作业完成时开始重定位,我们可以使用relocator,但是我们需要再推一个"STOP_FLAG",因为我们将有2个进程重新定位

    def creator(comm_q):
        for i in range(100):
            comm_q.put(create(i))
        for _ in range(2):
            comm_q.put("STOP_FLAG")
        relocator(comm_q)
    

    让我们说我们现在需要任意数量的重定位器进程,我们应该调整一下我们的代码来处理这个问题,我们需要creator方法知道有多少标志通知其他进程何时到停止,我们生成的代码看起来像这样:

    from multiprocessing import Process, Queue, cpu_count
    
    comm_queue = Queue()
    
    #process that create the files and push the data into the queue
    def creator(comm_q, number_of_subprocesses):
        for i in range(100):
            comm_q.put(create(i))
        for _ in range(number_of_subprocesses + 1): # we need to count ourselves
            comm_q.put("STOP_FLAG")
        relocator(comm_q)
    
    #the relocator works till it gets an stop flag
    def relocator(comm_q):
        data = comm_q.get()
        while data != "STOP_FLAG":
            if data:
                relocate(data, to_path_you_may_want)
            data = comm_q.get()
    
    num_of_cpus = cpu_count() #we will spam as many processes as cpu core we have
    creator_process= Process(target=creator, args=(comm_queue, num_of_cpus))
    relocators = [Process(target=relocator, args=(comm_queue)) for _ in num_of_cpus]
    creator_process.start()
    for rp in relocators:
        rp.start()
    

    然后你必须等待才能完成:

    creator_process.join()
    for rp in relocators:
        rp.join()
    

    您可以查看multiprocessing.Queue documentation

    特别是get method(默认情况下是阻止调用)

      

    从队列中删除并返回一个项目。如果是可选的args块   True(默认值),超时为None(默认值),阻止if   必要的,直到一个项目可用。