我們都知道并發(fā)(不是并行)編程目前有四種方式,多進(jìn)程,多線程,異步,和協(xié)程。
多進(jìn)程編程在python中有類似C的os.fork,當(dāng)然還有更高層封裝的multiprocessing標(biāo)準(zhǔn)庫,在之前寫過的python高可用程序設(shè)計方法中提供了類似nginx中master process和worker process間信號處理的方式,保證了業(yè)務(wù)進(jìn)程的退出可以被主進(jìn)程感知。
多線程編程python中有Thread和threading,在linux下所謂的線程,實際上是LWP輕量級進(jìn)程,其在內(nèi)核中具有和進(jìn)程相同的調(diào)度方式,有關(guān)LWP,COW(寫時拷貝),fork,vfork,clone等的資料較多,這里不再贅述。
異步在linux下主要有三種實現(xiàn)select,poll,epoll,關(guān)于異步不是本文的重點(diǎn)。
說協(xié)程肯定要說yield,我們先來看一個例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#coding=utf-8 import time import sys # 生產(chǎn)者 def produce(l): i = 0 while 1 : if i < 5 : l.append(i) yield i i = i + 1 time.sleep( 1 ) else : return # 消費(fèi)者 def consume(l): p = produce(l) while 1 : try : p. next () while len (l) > 0 : print l.pop() except StopIteration: sys.exit( 0 ) l = [] consume(l) |
在上面的例子中,當(dāng)程序執(zhí)行到produce的yield i時,返回了一個generator,當(dāng)我們在custom中調(diào)用p.next(),程序又返回到produce的yield i繼續(xù)執(zhí)行,這樣l中又append了元素,然后我們print l.pop(),直到p.next()引發(fā)了StopIteration異常。
通過上面的例子我們看到協(xié)程的調(diào)度對于內(nèi)核來說是不可見的,協(xié)程間是協(xié)同調(diào)度的,這使得并發(fā)量在上萬的時候,協(xié)程的性能是遠(yuǎn)高于線程的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import stackless import urllib2 def output(): while 1 : url = chan.receive() print url f = urllib2.urlopen(url) #print f.read() print stackless.getcurrent() def input (): f = open ( 'url.txt' ) l = f.readlines() for i in l: chan.send(i) chan = stackless.channel() [stackless.tasklet(output)() for i in xrange ( 10 )] stackless.tasklet( input )() stackless.run() |
關(guān)于協(xié)程,可以參考greenlet,stackless,gevent,eventlet等的實現(xiàn)。