multiprocessing 基于进程的“线程式”接口 python

来源:互联网 发布:淘宝上如何找真弩 编辑:程序博客网 时间:2024/04/29 02:02

multiprocessing在python2.6+版本中得到应用。

multi意思为多个,processing意思为进程 也就是实现多进程。可以实现利用调用计算机的多个CPU实现多线程。

multiprocessing是一个包,支持使用类似threading模块的API生成进程。multiprocessing包提供本地和远程两种并发,通过使用子进程而非线程有效地回避了全局解释器锁。 因此,multiprocessing模块允许程序员充分利用一个给定机器的多个处理器。它在Unix和Windows上都可允许。

下面主要介绍进程类

线程是通过创建Process对象,然后调用start()方法来产生的。Process继承了threading.Thread的API。现在举一个multiprocess 的例子:
使用Process创建进程:

from multiprocessing import Processdef f(name):    print 'hello', nameif __name__ == '__main__':    p = Process(target=f, args=('bob',)) #创建一个线程    p.start() #调用start方法 启动    p.join()  

下面是一个活的线程ID的例子:

from multiprocessing import Processimport osdef info(title):    print title    print 'module name:', __name__    if hasattr(os, 'getppid'):  # 只在Unix中可使用        print 'parent process:', os.getppid()    print 'process id:', os.getpid()def f(name):    info('function f')    print 'hello', nameif __name__ == '__main__':    info('main line')    p = Process(target=f, args=('bob',))    p.start()    p.join()

代码中使用os的getpid()获得父进程的ID 使用getip()获得当前进程的ID,另外还可以使用getppid获得父进程的父进程的ID。

IPC(Inter-Process Communication) 进程间的通信

multiprocessing包中有Pipe类和Queue类来分别支持这两种IPC机制。Pipe和Queue可以用来传送常见的对象。
Pipe可以是单向(half-duplex),也可以是双向(duplex)。我们通过mutiprocessing.Pipe(duplex=False)创建单向管道 (默认为双向)。一个进程从PIPE一端输入对象,然后被PIPE另一端的进程接收,单向管道只允许管道一端的进程输入,而双向管道则允许从两端输入。
举例:(单向的)

from multiprocessing import Process, Pipedef f(conn): #conn为父线程传递过来的pipe对象    conn.send([42, None, 'hello']) #在pipe对象的一端发送数据    conn.close() #关闭if __name__ == '__main__':    parent_conn, child_conn = Pipe() #定义两个Pipe对象来创建     p = Process(target=f, args=(child_conn,))#创建一个进程 传递的参数为pipe对象    p.start()    print parent_conn.recv()   # prints "[42, None, 'hello']" #在父进程中使用另一个pipe对象的recv()方法接受数据    p.join()

每个连接对象都有send和recv方法,需要注意的是,如果两个进程或者线程同时读取或写入pipe对象的终端,则可能引起终端。如果同时使用pipe的不同终端则不会有风险。

下面举例:(双向)

import multiprocessing as muldef proc1(pipe):    pipe.send('hello')    print('proc1 rec:',pipe.recv())def proc2(pipe):    print('proc2 rec:',pipe.recv())    pipe.send('hello, too')if __name__ == '__main__':    mul.freeze_support()    pipe1,pipe2= mul.Pipe() #创建两个pipe对象    # Pass an end of the pipe to process 1    p1 = mul.Process(target=proc1, args=(pipe1,)) #创建p1线程    # Pass the other end of the pipe to process 2    p2   = mul.Process(target=proc2, args=(pipe2,)) #创建p2线程    p1.start() #调用线程1    p2.start()  #调用线程2    p1.join()  #这里等待线程1执行完成    p2.join()  #等待线程2执行完成#输出:('proc2 rec:', 'hello')('proc1 rec:', 'hello, too')

这个例子实现了两个线程之间的通信,实现了双向通信。线程1: proc1中发送”hello”字符串,线程proc2中接收线程1proc1中发送的”hello”字符串并输出,然后proc2发送”hello, too”字符串,线程1 proc1接收到proc2发送的字符串并输出。

下面介绍另外一种实现IPC的方式:
Queue:
Queue与Pipe相类似,都是先进先出的结构。但Queue允许多个进程放入,多个进程从队列取出对象。Queue使用mutiprocessing.Queue(maxsize)创建,maxsize表示队列中可以存放对象的最大数量。
下面的程序展示了Queue的使用:

from multiprocessing import Process, Queuedef f(q):    q.put([42, None, 'hello'])  #调用主函数中p进程传递过来的进程参数 put函数为向队列中添加一条数据。if __name__ == '__main__':    q = Queue() #创建一个Queue对象    p = Process(target=f, args=(q,)) #创建一个进程    p.start()    print q.get()    # prints "[42, None, 'hello']"    p.join()

上面是一个queue的简单应用,使用队列q对象调用get函数来取得队列中最先进入的数据。
举一个复杂些的例子:

import multiprocessingimport time# 向queue中输入数据的函数def inputQ(queue):    info = str(os.getpid()) + '(put):' + str(time.time())    queue.put(info)# 向queue中输出数据的函数def outputQ(queue,lock):    info = queue.get()    lock.acquire()    print (str(os.getpid()) + '(get):' + info)    lock.release()# Mainif __name__ == '__main__':    multiprocessing.freeze_support()    record1 = []   # store input processes    record2 = []   # store output processes    lock  = multiprocessing.Lock()    #使用锁方法输出错乱    queue = multiprocessing.Queue(3)    # 输入进程    for i in range(10):        process = multiprocessing.Process(target=inputQ,args=(queue,))        process.start()        record1.append(process)    # 输出进程    for i in range(10):        process = multiprocessing.Process(target=outputQ,args=(queue,lock))        process.start()        record2.append(process)    for p in record1:        p.join()    queue.close()  # 如果没有数据进入队列中则关闭队列    for p in record2:        p.join()#输出结果为:15212(get):7180(put):1440649672.228820(get):7020(put):1440649672.856164(get):7872(put):1440649673.3910904(get):9436(put):1440649673.685016(get):16840(put):1440649674.0712004(get):12848(put):1440649674.3814456(get):11608(put):1440649674.662468(get):16884(put):1440649674.856464(get):8944(put):1440649674.897576(get):15476(put):1440649674.92

这个例子中,创建了二十个进程,十个是用来写入队列数据的,另外十个是用来输出队列中的数据的。

1 0
原创粉丝点击