三、进程和线程、协程在python中的使用
1、多进程一般使用multiprocessing库,来利用多核CPU,主要是用在CPU密集型的程序上,当然生产者消费者这种也可以使用。多进程的优势就是一个子进程崩溃并不会影响其他子进程和主进程的运行,但缺点就是不能一次性启动太多进程,会严重影响系统的资源调度,特别是CPU使用率和负载。使用多进程可以查看文章《python 多进程使用总结》。注:python2的进程池在类中的使用会有问题,需要把类函数定义成全局函数。具体可参考 http://bbs.chinaunix.net/thread-4111379-1-1.html
2、多线程一般是使用threading库,完成一些IO密集型并发操作。多线程的优势是切换快,资源消耗低,但一个线程挂掉则会影响到所有线程,所以不够稳定。现实中使用线程池的场景会比较多,具体可参考《python线程池实现》。
3、协程一般是使用gevent库,当然这个库用起来比较麻烦,所以使用的并不是很多。相反,协程在tornado的运用就多得多了,使用协程让tornado做到单线程异步,据说还能解决C10K的问题。所以协程使用的地方最多的是在web应用上。
总结一下就是IO密集型一般使用多线程或者多进程,CPU密集型一般使用多进程,强调非阻塞异步并发的一般都是使用协程,当然有时候也是需要多进程线程池结合的,或者是其他组合方式。
下面我们使用进程加协程来做加法和乘法的计算任务同时计算,也就是并发计算:
# coding:utf-8 import gevent import multiprocessing,os import time def f1(s): a = s while a<33: a = a + 1 print('计算相加 进程ID:%s'%os.getpid(),a) # gevent.sleep(1) def f2(s): d=1 for i in range(s,30): d = d*i print('计算相乘 进程ID:%s'%os.getpid(),d) # gevent.sleep(1) def gv1(i): g1 = gevent.spawn(f1, i) g1.join() def gv2 (i): g2 = gevent.spawn(f2, i) g2.join() if __name__=='__main__': start = time.clock() # # 进程池 # pool = multiprocessing.Pool(2) # pool.apply_async(gv1,(1,)) # pool.apply_async(gv2,(1,)) # pool.close() # pool.join() # 单开进程 pool = [] p1 = multiprocessing.Process(target=f1,args=(1,)) p2 = multiprocessing.Process(target=f2,args=(1,)) pool.append(p1) pool.append(p2) p1.start() p2.start() for item in pool: item.join() print(time.clock()-start)
自动化学习。