python学习笔记四(python多进程)

来源:互联网 发布:c语言 udp多线程编程 编辑:程序博客网 时间:2024/06/16 07:06

写之前在犹豫,是否需要将多线程放在这个之前讲或者将多线程和多进程合到一起讲python的并发性,鉴于内容较多,还是分为两个吧。

这次将介绍multiprocessing模块的用法、怎么写多进程程序、进程间通信、进程间数据共享等。由于python使用了内部的GIL,在任意时刻只允许单个线程运行,无论系统有多少个CPU,程序只能在一个CPU上运行,这导致资源的极大浪费。所以多进程的出现可以很好的解决这个问题。说到进程,可能首先想到的是os和subprocess模块中创建子进程的函数,但是多进程和这个还是有区别的,在处理问题上有一定的区别。闲话少说,进入正题。

1、创建进程

#coding=utf-8from multiprocessing import Processfrom time import sleepdef work(param):    while True:        print param        sleep(1)if __name__ == '__main__':    param = 'test'    process = Process(target=work, args=(param,), name= 'process1')    # process.daemon = True    process.start()    print process.pid    print process.name    sleep(1)    # process.join()
上述方法为比较常用的创建多进程的方法,也可以自己实现一个类,继承Process类,并重写run方法,同样可以达到目的。

使用Process时,target为要调用的函数名,args为函数需要的参数(一个元组),name为进程名。

可以通过Process对象拿到创建进程的进程名和ID。

daemon=True表示创建的进程为后台进程,当主进程执行完后子进程也会退出,否则挂起等待子进程退出。

join函数表示此时主进程等待,直到子进程执行完毕。

2、进程池

在需要创建多个(成百上千)进程的时候,靠人工一个个复制显然行不通,multiprocessing模块提供了一个线程池来解决这个问题。

# encoding: UTF-8 import multiprocessing,time def func(msg):    for i in xrange(3):        print msg        time.sleep(1)    return "done " + msg if __name__ == "__main__":    pool = multiprocessing.Pool(processes=4)    result = []    for i in xrange(10):        msg = "hello %d" %(i)        result.append(pool.apply_async(func, (msg, )))    pool.close()    pool.join()    for res in result:        print res.get()
先解释下上面的代码,循环地将进程加到进程池并发执行,apply_async会异步执行函数,然后返回结果,是一个AsyncResult类的实例,稍后可以通过get函数获取结果,但是get函数是一个阻塞的。除了apply_async函数,还有其他函数会用到:

apply:该函数不会在多个进程中并发的执行func函数,如果要通过不同参数并发执行func函数,则最好使用apply_async函数。

map:可以将被调用对象func应用给参数iterable中的每一个项,并返回执行结果。如果不需要得到返回结果,这个函数是可以使用的,如果要返回结果,则用map_async函数。

map_async:跟map一样,但是返回的结果是一个AsyncResult对象,可以稍后回去结果。

一般情况下,apply_async函数或map就够用。

3、进程间通信

multiprocessing模块支持进程间通信有两种形式:队列和管道。都是使用消息传递实现的。

# encoding: UTF-8import multiprocessing,timedef consumer(input_q):    while True:        item = input_q.get()        print item        #发信号通知任务完成        input_q.task_done()def producer(sequence,output_q):    for item in sequence:        output_q.put(item)if __name__ == "__main__":    q = multiprocessing.JoinableQueue()    cons_p = multiprocessing.Process(target=consumer, args=(q,))    cons_p.daemon = True    cons_p.start()    sequence = [1,2,34,5,]    producer(sequence,q)    q.join()
这个跟C里的队列基本一样,只是JoinableQueue加入了task_done等属性,管道的用法也类似,这里就不介绍了。

4、共享内存数据

def worker(num, mystr, arr):    num.value *= 2    mystr.value = str(os.getpid())    for i in range(len(arr)):        arr[i] = arr[i] * -1 + 1.5def dump_vars(num, mystr, arr):    print 'num: ', num.value    print 'str: ', mystr[:]    print 'arr: ', arr[:]def test_sharedmemory():    num = Value('i', 5)    mystr = Array('c', 'just for test')    arr = Array('d', [1.0, 1.5, -2.0])    print 'init value'    dump_vars(num, mystr, arr)    ps = [Process(target=worker, args=(num, mystr, arr)) for _ in range(3)]    for p in ps:        p.start()    for p in ps:        p.join()    print    print 'after all workers finished'    dump_vars(num, mystr, arr)if __name__=='__main__':    test_sharedmemory()

这部分自己平时没怎么用过,上述代码是从别的地方copy过来的,留个记录,以后要用的时候可以再参考下。

5、总结

上述的几个都比较浅显,还有一些东西给略过了如Manager。今天的这些东西看了一下午,头都大了,写到后面的两节时快没心思,以后得克服。


0 0