Python多处理:结束无限计数器

时间:2013-09-30 13:47:24

标签: python multiprocessing

我是多处理的新手,我只是想在Python 3.2中编写一个简单的程序,它在一个线程中有一个无限增加的计数器,而第二个线程检查是否已经在一个线程中达到一个给定的值。第一个帖子。达到该值后,我希望关闭多处理线程,并让程序显示“Process Complete”语句。

据我了解,该程序看起来像(给定值为10):

import multiprocessing as mp


def Counter():
    i=1
    while i > 0:
        print("i: ",i)
        i+=1


def ValueTester(i):
    if i >= 10:
        *End Counter Function Thread*


if __name__ == '__main__':

    *Begin multiprocessing, one thread for "Counter" and a second for "ValueTester"*

    print("Process Complete")

我为伪代码的含糊不清道歉;我已经阅读了Python文档以及几个不同的示例,我似乎无法找到一个简单的解决方案。

此外,一旦这个工作,我将如何设置给定的停止值(即将变量传递给ValueTester,而不是仅使用10)?

非常感谢你的帮助。

2 个答案:

答案 0 :(得分:4)

我们需要注意在线程和进程之间做出明确区分。

线程都在相同的进程下运行。可以共享访问的值 线程之间。安全(协调)中的线程可以更改值 只有当值在threading.Lock之前受到保护时才会使用 改变。在CPython中,最常见的Python实现和PyPy,但是 与其他实现相比,如Jython或Iron Python,GIL(全球 解释器锁)防止多个线程在任何给定的情况下运行 时间。所以在CPython下,多个线程实际上是串行运行的,而不是 同时。尽管如此,多线程对于I / O关注工作仍然有用 作为查询许多网站,因为大部分时间都在等待 用于网络(I / O)活动。因此多线程不必等待 同样,与任务相比,争取访问单个CPU 像数学计算一样是CPU密集型的。

现在说了这么多,你正在处理多个进程,而不是 线程。流程彼此独立。他们可以并且确实可以运行 同时在多个CPU上(如果可用)(包括在CPython下)。当你 生成一个进程,将全局值从原始进程复制到 产生的过程。在某些操作系统上,比如Linux,它们具有“写时复制”功能 实际上,在进程尝试进行之前,进程之间会共享值 覆盖一个值,此时该值被复制为独立于 另一个过程。因此,当您修改值时,两个进程最终会有两个 变量名称相同但可以具有完全不同的值

多处理模块提供了特殊对象以方便使用 sharing state between processes。其中包括mp.Valuemp.Arraymp.Manager。请注意,当您使用这些对象时you must also use a mp.Lock 防止一个进程更改值,而另一个进程尝试执行相同操作 事情。但是,Lock也会减慢进程,因为必须等待 锁定被释放。

现在,当在另一个流程中达到条件时发出流程信号,请使用mp.Event

import multiprocessing as mp
import time

def Counter(i, event, lock):
    with lock:
        i.value = 1
    while i.value > 0 and not event.is_set():
        print("i: ", i.value)
        with lock:
            i.value += 1


def ValueTester(i, stopval, event):
    while True:
        if i.value >= stopval:
            event.set()
            break
        else:
            time.sleep(0.1)


if __name__ == '__main__':
    num = mp.Value('d', 0.0)
    # A lock is not absolutely necessary here since only one process modifies
    # num, but I'm including it since it is necessary (to avoid race conditions)
    # in the more usual case when multiple processes may modify num.
    lock = mp.Lock()
    event = mp.Event()
    counter = mp.Process(target=Counter, args=(num, event, lock))
    counter.start()
    tester = mp.Process(target=ValueTester, args=(num, 10, event))
    tester.start()
    tester.join()
    counter.join()
    print("Process Complete")

有关如何使用多处理的更多示例,请参阅Doug Hellman's Python Module of the Week tutorial

答案 1 :(得分:1)

所以你需要的是两个线程(进程)相互通信的机制。幸运的是,Python的多处理模块为您提供了一些选项,其中一个是队列。

所以要做的第一件事就是启动这两个def,然后传入一个可以用来进行通信的共享队列。由于您希望主进程终止子进程,因此第一个进程应该从第二个进程开始。

import multiprocessing as mp
from multiprocessing import Queue

def counter(): #use lowercase c, 'Counter' is importable
    threshold = 10
    output = Queue(1) #for placing numbers on the queue
    input = Queue(1) #for looking for the signal that child is done
    child = Process(target=valuetester, args=(threshold, output, input))
    child.start()
    i=1
    while i > 0:
        output.put(i)
        print("i: ",i)
        i+=1 
        try:
            done = input.get_nowait()
            if done == 'Im Done!':
                print 'Process Complete!'
                child.join() #clean up the child proc
                return
        except Empty:
            pass #input is empty, no big deal


def valuetester(threshold, input, output):
    thresholdNotPassed = False
    while thresholdNotPassed:
        i = input.get()
        if i >= threshold:
            output.put('Im Done!')
            return 
        else:
            pass #nothing to do... just wait

#Start the counter proc. You could use the main process since its easier
if __name__ == 'main':
    counter()

有几点需要注意: 我让队列的maxsize为1 ...如果队列已满,这将会阻塞(保持在该行)。

你可以看到我还使用get_nowait()为主进程检查子进程是否已完成,否则使用普通get会阻塞,我们会死锁!