python multiprocessing.Pipe() Queue 示例

来源:互联网 发布:我知女人心阮琦 编辑:程序博客网 时间:2024/05/18 00:41
#!/usr/bin/env python#This requires Python2.5 or greaterfrom threading import Threadimport subprocessfrom Queue import Queueimport renum_ping_threads = 5num_arp_threads = 5in_queue = Queue()out_queue = Queue()ips = []for i in range(1,254):    ips.append("192.168.1.%i" %i)#Place ip addresses into in queuefor ip in ips:    in_queue.put(ip)def pinger(i, iq, oq):    """Pings subnet"""    while True:        ip = iq.get()        print "Thread %s: Pinging %s" % (i, ip)        ret = subprocess.call(  "ping -c 1 %s" % ip,                                shell=True,                                stdout=open('/dev/null', 'w'),                                stderr=subprocess.STDOUT)        if ret == 0:            #print "%s: is alive" % ip            #place valid ip address in next queue            oq.put(ip)        else:            print "%s: did not respond" % ip        iq.task_done()def arping(i, oq):    """grabs a valid IP address from a queue and gets macaddr"""    while True:        ip = oq.get()        p = subprocess.Popen(   "arping -c 1 %s" % ip,                                shell=True,                                stdout=subprocess.PIPE)        out = p.stdout.read()        #match and extract mac address from stdout        result = out.split()        pattern = re.compile(":")        macaddr = None        for item in result:            if re.search(pattern, item):                macaddr = item        print "IP Address: %s | Mac Address: %s " % (ip, macaddr)        oq.task_done()#spawn pool of ping threadsfor i in range(num_ping_threads):    worker = Thread(target=pinger, args=(i, in_queue, out_queue))    worker.setDaemon(True)    worker.start()#spawn pool of arping threadsfor i in range(num_arp_threads):    worker = Thread(target=arping, args=(i, out_queue))    worker.setDaemon(True)    worker.start()print "Main Thread Waiting"in_queue.join()out_queue.join()

我们已经见过了使用subprocess包来创建子进程,但这个包有两个很大的局限性:1) 我们总是让subprocess运行外部的程序,而不是运行一个Python脚本内部编写的函数。2) 进程间只通过管道进行文本交流。以上限制了我们将subprocess包应用到更广泛的多进程任务。(这样的比较实际是不公平的,因为subprocessing本身就是设计成为一个shell,而不是一个多进程管理包)

 

threading和multiprocessing

(请尽量先阅读Python多线程与同步)

multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情境。

但在使用这些共享API的时候,我们要注意以下几点:

  • 在UNIX平台上,当某个进程终结之后,该进程需要被其父进程调用wait,否则进程成为僵尸进程(Zombie)。所以,有必要对每个Process对象调用join()方法 (实际上等同于wait)。对于多线程来说,由于只有一个进程,所以不存在此必要性。
  • multiprocessing提供了threading包中没有的IPC(比如Pipe和Queue),效率上更高。应优先考虑Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (因为它们占据的不是用户进程的资源)。
  • 多进程应该避免共享资源。在多线程中,我们可以比较容易地共享资源,比如使用全局变量或者传递参数。在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。此时我们可以通过共享内存和Manager的方法来共享资源。但这样做提高了程序的复杂度,并因为同步的需要而降低了程序的效率。

Process.PID中保存有PID,如果进程还没有start(),则PID为None。

 

我们可以从下面的程序中看到Thread对象和Process对象在使用上的相似性与结果上的不同。各个线程和进程都做一件事:打印PID。但问题是,所有的任务在打印的时候都会向同一个标准输出(stdout)输出。这样输出的字符会混合在一起,无法阅读。使用Lock同步,在一个任务输出完成之后,再允许另一个任务输出,可以避免多个任务同时向终端输出。

#!/usr/bin/python#coding=utf-8''' Pipe可以是单向(half-duplex),也可以是双向(duplex)。我们通过mutiprocessing.Pipe(duplex=False)创建单向管道 (默认为双向)。 一个进程从PIPE一端输入对象,然后被PIPE另一端的进程接收,单向管道只允许管道一端的进程输入,而双向管道则允许从两端输入。Pipe对象建立的时候,返回一个含有两个元素的表,每个元素代表Pipe的一端(Connection对象)。我们对Pipe的某一端调用send()方法来传送对象,在另一端使用recv()来接收。'''import os,threadingfrom multiprocessing import Process, Pipedef send(pipe,i):    pipe.send(dict(name = 'send',pid=os.getpid()))    pipe.close()def talk(pipe,i):    pipe.send(dict(name = 'talk', process = i, pid = os.getpid()))    print('child got:', pipe.recv())def worker(sign, lock):    lock.acquire()    print(sign+str(os.getpid()))    lock.release()# Multi-threaddef Multi_thread():    record = []    lock = threading.Lock()    for i in range(5):        thread = threading.Thread(target=worker, args=('thread:', lock))        thread.start()        record.append(thread)    for thread in record:        thread.join()if __name__ == '__main__':    pipe1 = Pipe()    pipe2 = Pipe()    record = []    for i in range(3):        sender = Process(target = send, args = (pipe1[0],i))        sender.start()        record.append(sender)    for i in record:        print "pipe1[1] got pipe1[0] : %s" % pipe1[1].recv()#从send收到消息    pipe1[1].close()    for i in range(3):        parent = Process(target = talk, args = (pipe2[1],i))        parent.start()        print('parent got:', pipe2[0].recv())        pipe2[0].send("parent send msg to chile.")        parent.join()    # Multi-thread    Multi_thread()


0 0
原创粉丝点击