Python:使用Multiprocess切换功能

时间:2014-09-10 17:43:27

标签: python multiprocessing

我试图在python中学习多处理。

我想要发生的是随着时间的推移x增加,然后当我点击'输入'它会随着时间的推移而减少,我可以继续按下Enter键从增加切换到减少。

到目前为止,我所做的一切都是

import time
from multiprocessing import Pool

def f(x):
    return (x+1)
def f1(x):
    return (x-1)

if __name__ == '__main__':
    pool = Pool(processes=2)
    x=0
    while x<100:
        x = pool.apply_async(f, [10])
        time.sleep(0.05)

我无法查看文档,因为他们没有提供明确的示例。 请帮忙我不知道

2 个答案:

答案 0 :(得分:2)

汇总了一个例子来给你一些想法。

#!/usr/bin/python3
import time
from multiprocessing import Pool, Manager
from threading import Thread

NUM_PROCESSES = 4

def consumer(q):
    out = []
    while True:
        val = q.get()
        if val is None:
            #poison pill
            break
        #doing some work here
        time.sleep(0.01)
        out.append(val)
    return out

def producer(queue):
    flip = True
    val = 5

    def flipper():
        nonlocal flip
        input('enter to flip it!')
        while True:
            flip = not flip
            txt = 'up' if flip else 'down'
            input('val is {}, now counting {}'.format(val, txt))

    t = Thread(target=flipper, args=(), daemon=True)
    t.start()

    while val > 0:
        for _ in range(NUM_PROCESSES):
            queue.put(val)
        val = val + (1 if flip else -1)
        time.sleep(0.2)

    print()
    print('hit zero, shutting down.')

    for _ in range(NUM_PROCESSES):
        #poison pills
        queue.put(None)

if __name__ == '__main__':
    pool = Pool(processes=NUM_PROCESSES)
    m = Manager() # N.B.: multiprocessing.Queue doesn't work with Pool.apply_async
    q = m.Queue()

    results = pool.apply_async(consumer, args=(q,))
    producer(q) # running in main thread because I'm lazy

    print(results.get())

输出:

ben@nixbox:~$ python3 multithread.py 
enter to flip it!
val is 13, now counting down
val is 4, now counting up
val is 8, now counting down
hit zero, shutting down.
[5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1]

原始代码的设置方式,并行化并没有多大意义。所以我改用生产者/消费者范例:你的制作人生产&#34;工作单位&#34;增加直到你点击进入,然后减少直到它达到零,然后它加载工作队列与毒丸,告诉消费者关闭。有一些技巧可以让输入/翻转的东西工作,但我会让你看看代码。请注意,我使用 threads 等待阻塞I / O操作,进程执行(模拟)CPU繁重的工作。这是故意的。

有很多方法可以构建多处理代码,但我发现生产者/消费者是一个非常有用的模式。你真正想要做的一件事就是迅速创建流程来完成少量的工作,然后将它们拆除。这是! (我会注意到正确地使用Pool可以避免这种情况 - 它可以让你的工作人员保持活着。但是,值得一提的是,因为很多人开始通过在一个循环中触发一堆Process es,然后想知道为什么他们的并行代码比他们的单线程代码慢: - ))

答案 1 :(得分:1)

这不是测试multiprocessing的好方法。您正在对x执行无法实际有效的操作 - 您只希望一个进程能够一次增加x。否则,不同的工人会踩踏其他工人设定的x值。而且,由于你所有的工作人员都在增加x,所以他们基本上需要完全按顺序运行,而不需要并发运行。

也就是说,要使此代码正常工作,您需要实际从apply_async返回的AsyncResult对象中获取实际结果:

import time
from multiprocessing import Pool

def f(x):
    return (x+1)
def f1(x1):
    return (x-1)

if __name__ == '__main__':
    pool = Pool(processes=2)
    x=0
    while x<100:
        x = pool.apply_async(f, [x]).get()  # Added get, changed 10 to x
        time.sleep(0.05)

添加get调用将使主进程阻塞,直到工作人员实际完成为止。当然,这意味着你并没有真正做到平行,但这确实是安全增加变量的唯一方法。