Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 带while循环的基本多处理_Python_Python 2.7_While Loop_Multiprocessing_Python Multiprocessing - Fatal编程技术网

Python 带while循环的基本多处理

Python 带while循环的基本多处理,python,python-2.7,while-loop,multiprocessing,python-multiprocessing,Python,Python 2.7,While Loop,Multiprocessing,Python Multiprocessing,我是python中的多处理包的新手,我的困惑可能很容易被了解更多的人弄清楚。我一直在阅读有关并发性的文章,并搜索了其他类似的问题,但没有找到任何结果。(仅供参考,我不想使用多线程,因为GIL会大大降低我的应用程序的速度。) 我在事件的框架中思考。我想让多个进程运行,等待事件发生。如果事件发生,它将被分配给一个特定的进程,该进程将运行,然后返回到空闲状态。也许有更好的方法可以做到这一点,但我的理由是,我应该一次生成所有进程,并让它们无限期地打开,而不是每次事件发生时创建然后关闭一个进程。速度对我来

我是python中的
多处理
包的新手,我的困惑可能很容易被了解更多的人弄清楚。我一直在阅读有关并发性的文章,并搜索了其他类似的问题,但没有找到任何结果。(仅供参考,我不想使用
多线程
,因为GIL会大大降低我的应用程序的速度。)

我在事件的框架中思考。我想让多个进程运行,等待事件发生。如果事件发生,它将被分配给一个特定的进程,该进程将运行,然后返回到空闲状态。也许有更好的方法可以做到这一点,但我的理由是,我应该一次生成所有进程,并让它们无限期地打开,而不是每次事件发生时创建然后关闭一个进程。速度对我来说是个问题,我的事件每秒可能发生数千次

我提出了下面的玩具示例,它意味着向一个进程发送偶数,向另一个进程发送奇数。这两个过程是相同的,它们只是将数字附加到列表中

from multiprocessing import Process, Queue, Pipe

slist=['even','odd']

Q={}
Q['even'] = Queue()
Q['odd'] = Queue()

ev,od = [],[]

Q['even'].put(ev)
Q['odd'].put(od)

P={}
P['even'] = Pipe()
P['odd'] = Pipe()



def add_num(s):
    """ The worker function, invoked in a process. The results are placed in
        a list that's pushed to a queue."""
#    while True :
    if not P[s][1].recv():
        print s,'- do nothing'

    else:            
        d = Q[s].get()
        print d
        d.append(P[s][1].recv())
        Q[s].put(d)
        print Q[s].get()
        P[s][0].send(False)
        print 'ya'




def piper(s,n):

    P[s][0].send(n)    
    for k in [S for S in slist if S != s]:
        P[k][0].send(False) 
    add_num(s)


procs = [ Process (
                   target=add_num,
                   args=(i,)
                   ) 
         for i in ['even','odd']]

for s in slist: 
    P[s][0].send(False)

for p in procs:
    p.start()  
    p.join()

for i in range(10):
    print i
    if i%2==0:
        s = 'even'
    else:
        s = 'odd'
    piper(s,i)


print 'results:', Q['odd'].get(),Q['even'].get()
此代码生成以下内容:

偶数-什么也不做


如果智者能洞察这个问题,如果我的代码或推理有不足之处,我们将不胜感激

以下是一种我已经使用过好几次并取得成功的方法:

  • 发动一场战争

  • 使用多处理创建多个队列(每种类型的数据一个队列,需要进行不同的处理)

  • 用于启动处理数据的功能。与队列一样,对于需要进行不同处理的每种类型的数据,应该有一个函数。启动的每个函数都会获取与其数据对应的队列作为输入参数。这些函数将在一个无限循环中完成它们的工作,该循环从队列中获取数据开始

  • 开始处理。在处理过程中,主进程对数据进行排序,并决定哪个函数应该处理它。一旦做出决定,数据将被放置在与该函数对应的队列上

  • 处理完所有数据后,主进程将一个名为“毒丸”的值放入每个队列。毒丸是工作人员处理的所有人都识别为退出信号的值。由于队列是先进先出(FIFO),因此它们保证将毒药丸作为队列中的最后一项取出

  • 关闭并加入多处理池

  • 代码 下面是这个算法的一个例子。示例代码的目标是使用前面描述的算法将奇数除以2,将偶数除以-2。所有结果都放在主进程可访问的共享列表中

    import multiprocessing
    
    POISON_PILL = "STOP"
    
    def process_odds(in_queue, shared_list):
    
        while True:
    
            # block until something is placed on the queue
            new_value = in_queue.get() 
    
            # check to see if we just got the poison pill
            if new_value == POISON_PILL:
                break
    
            # we didn't, so do the processing and put the result in the
            # shared data structure
            shared_list.append(new_value/2)
    
        return
    
    def process_evens(in_queue, shared_list):
    
        while True:    
            new_value = in_queue.get() 
            if new_value == POISON_PILL:
                break
    
            shared_list.append(new_value/-2)
    
        return
    
    def main():
    
        # create a manager - it lets us share native Python object types like
        # lists and dictionaries without worrying about synchronization - 
        # the manager will take care of it
        manager = multiprocessing.Manager()
    
        # now using the manager, create our shared data structures
        odd_queue = manager.Queue()
        even_queue = manager.Queue()
        shared_list = manager.list()
    
        # lastly, create our pool of workers - this spawns the processes, 
        # but they don't start actually doing anything yet
        pool = multiprocessing.Pool()
    
        # now we'll assign two functions to the pool for them to run - 
        # one to handle even numbers, one to handle odd numbers
        odd_result = pool.apply_async(process_odds, (odd_queue, shared_list))
        even_result = pool.apply_async(process_evens, (even_queue, shared_list))
        # this code doesn't do anything with the odd_result and even_result
        # variables, but you have the flexibility to check exit codes
        # and other such things if you want - see docs for AsyncResult objects
    
        # now that the processes are running and waiting for their queues
        # to have something, lets give them some work to do by iterating
        # over our data, deciding who should process it, and putting it in
        # their queue
        for i in range(6):
    
            if (i % 2) == 0: # use mod operator to see if "i" is even
                even_queue.put(i)
    
            else:
                odd_queue.put(i)
    
        # now we've finished giving the processes their work, so send the 
        # poison pill to tell them to exit
        even_queue.put(POISON_PILL)
        odd_queue.put(POISON_PILL)
    
        # wait for them to exit
        pool.close()
        pool.join()
    
        # now we can check the results
        print(shared_list)
    
        # ...and exit!
        return
    
    
    if __name__ == "__main__":
        main()
    
    输出 此代码生成以下输出:

    [0.5,-0.0,1.5,-1.0,2.5,-2.0]

    请注意,结果的顺序是不可预测的,因为我们无法保证函数能够以什么顺序从其队列中获取项目并将结果放入列表。但是你当然可以选择任何你需要的后处理,包括排序

    根本原因 我认为这将是一个很好的解决方案,因为:

  • 您是对的,生成过程有巨大的开销。这种单一生产者/多消费者的方法消除了在整个项目期间使用人才库保持员工活力的情况

  • 它解决了您对能够根据数据属性以不同方式处理数据的担忧。在您的评论中,您表达了对能够向特定流程发送数据的担忧。在这种方法中,您可以选择向哪些进程提供数据,因为您必须选择将数据放在哪个队列上。(顺便说一句,我认为您考虑的是函数,正如您正确认为的那样,它不允许您在同一个作业中执行不同的操作。
    apply\u async

  • 我发现它非常具有可扩展性和灵活性。需要添加更多类型的数据处理吗?只需编写处理程序函数,再添加一个队列,并将逻辑添加到main,即可将数据路由到新函数。您是否发现一个队列正在备份并成为瓶颈?您可以使用相同的目标函数和队列多次调用
    apply\u async
    ,以使多个工人在同一队列上工作。只要确保你给排队的人足够的毒药,这样所有的工人都能得到一片

  • 局限性 要在队列上传递的任何数据都必须可由pickle模块拾取(序列化)。看看什么可以腌制,什么不可以腌制


    可能还有其他限制,但我想不出还有其他限制

    如果您想要一个单元素元组,那么需要在末尾加一个逗号,就像这样
    args=(i,)
    谢谢。这确实消除了我的错误。但由于某些原因,代码仍然不起作用。我已经编辑了上面的问题,以反映新的状态,并让它在我继续处理时保持打开状态。
    add_num
    函数中的
    print d
    语句应引发异常。True。我已经修复并再次更新。我现在需要停止这方面的工作,也许是最好的,因为它完全让我迷惑。@Wapiti你能解释一下你在这里到底想做什么吗?对每一个使用
    队列
    管道
    ,都会造成混乱。您还将调用
    queue.get
    queue.put
    ,然后再调用
    queue.get
    ,所有这些都在辅助函数内。为什么呢?第一个
    get
    调用如果碰到它,总是会导致死锁,因为您从来不会
    从父级向队列中放入任何内容。另外,您正在将
    False
    加载到两个管道中,启动子管道,当它们调用
    if not P[s][1]时,会看到
    False