python concurrence framework/library : http://wiki.python.org/moin/Concurrency/
棧溢出對該問題的討論帖:http://stackoverflow.com/questions/1824418/a-clean-lightweight-alternative-to-pythons-twisted
concurrence
1.並行編程
2.所有程式運行在tasklet中,由disptach啟動第一個tasklet,內部可以衍生出多個tasklet
3.tasklet.sleep(x)可以出讓CPU,time.sleep(x)會阻塞整個進程;不出讓CPU的情況下所有tasklet串列(序列化執行,且每個tasklet執行完了才到下一個tasklet);Tasklet.loop(func)指定的func如果內部沒有Tasklet.sleep(x)調用,就會導致整個進程陷入這個函數的死迴圈中;Tasklet.yield_()也可以出讓CPU,在CPU密集且沒有阻塞事件的tasklet內部一定要在迴圈中調用該方法出讓CPU(http://opensource.hyves.org/concurrence/concurrence.core.html#concurrence.core.Tasklet.yield_)
twisted (module index)
1.事件驅動編程
2.twisted.internet.protocol.Protocol:Protocol class隨著每個串連而執行個體化一個對象;隨著串連結束而消失。connectionMade串連建立的事件,connectionLost串連斷開的事件,dataReceived新資料事件。loseConnection()在資料發送完畢後才關閉串連,abortConnection()直接掐斷串連。
3. twisted.internet.protocol.Factory:一致化的配置(持久資料)由Factory提供,其buildProtocol方法為每個新的串連建立一個Protocol對象。Factory不監聽連接埠,因為我們可能需要對不同地址和連接埠提供一樣的服務,Factory不需要知道網路的事情。網路監聽相關的事情由endpoints相關的概念提供(ListenTCP,reactor)。Factory要實現應用程式指定的初始化和結束業務,可在startFactory()和stopFactory()內部完成,不能__init__和__del__中做,因為Factory一般是全程不消逝的執行個體。
4.endpoint監聽連接埠,reactor.run()啟動反應堆。reactor.stop() or ctrl+c 終止反應堆。
5.http協議是LineReceiver 和 rawDataReceived的混合體。對於LineReceiver protocol有兩個不同的事件處理函數,lineReceived 和 rawDataReceived,調用setRawMode()之後新資料到來會調用rawDataReceived ,直到 setLineMode()被調用才會切換到 lineReceived。 sendLine函數發送的資料加上行分隔字元(預設\r\n)。
6.兩種client編程方式(a更靈活,從factory往下都是一致的,要改變協議和地址連接埠只需修改endpoint相關邏輯;b更可控,有一些endpoint還不支援的low-level的操作,比如reconnection):a.endpoint,connect,這種模式connect傳入的必須是Factory而不能是ClientFactory; b.ClientFactory,reactor
7.單元測試,Test-Driven Development(TDD)->write tests first, make sure they fail, then do development.
8.application, twistd -y service.tac
concurrence vs twisted
1.concurrence有我中意的stackless+libevent,但是過於簡陋,在耗時的阻塞操作(一個tasklet阻塞住整個進程迴圈就會阻塞住)轉非同步作業上比較麻煩,比如調用第三方庫提供的介面(urllib2.urlopen(xx).read()),沒有直觀的非同步機制(官方文檔顯示資料庫查詢已經實現非同步了,沒試過),twisted沒有這個問題(可以用Deferred/deferToThread/callInThread等解決)
2.concurrence沒有twisted的protocol這個東東(twisted.internet.protocol.Protocol),從網路收到的資料需要自己讀取和解析不像twisted一樣有資料準備好的事件處理函數(myProtocol.dataReceived()/myProtocol.LineReceived())、對於串連斷開和建立成功也沒有封裝好的事件處理函數(myProtocol.connectionMade()/myProtocol.connectionLost()),都需要自己從零做起,比較耽誤時間
3.但是,twisted好龐大,這算是twisted對我而言難搞的主要問題,尤其是其TDD、twistd部署(tac檔案)、各種封裝好的協議(MAIL/DNS/SSL/..)、官網上手冊上那個什麼"Tutorial: Twisted From Scratch"之類的,一點都不想花心思瞭解
4.為了用上multiple cpu,兩者都需要引入多進程。twisted比較方便:twisted.internet.utils.getProcessOutput()/getProcessValue()執行子進程並拿到輸出或傳回值(Deferred非同步);twisted.internet.reactor.spawnProces()發動子進程+twisted.internet.protocol.ProcessProtocol協議用事件處理函數(connectionMade/terminateProcess/outReceived/errReceived/...)的方式跟子進程互動。上述這些concurrence是沒有的。而對於跟子進程以外的進程互動,比較簡單的方式是用tcp串連來做,那麼兩者對比就回到了前面提過的點上了(concurrence對串連建立/斷開/資料到達等沒有做封裝和提供事件處理函數)
5.還有個問題是兩者都沒有ORM,資料庫操作比較麻煩,如果能把django的ORM整合進來就爽歪歪了,貌似django-twisted是幹這活的,待老衲進去一探究竟?
---> [2013.6.24] 結果出爐,django-twisted(twango)這個項目已經老得跟不上django的步伐了(最新動向是兩年前)。據推測,當年django中count()/all()/none()跟filter()一樣可接收擴充位置參數和擴充關鍵字參數,README中的代碼需要改成下述樣子才可正常運行(TwistedQuerySet中連filter這些方法都沒有更說明twango這個項目很古老並且已被人拋棄):
import syssys.path.append('/home/dongsong/boosencms/src/')import osif not os.environ.has_key('DJANGO_SETTINGS_MODULE'): os.environ['DJANGO_SETTINGS_MODULE'] = 'boosencms.settings'else: print 'DJANGO_SETTINGS_MODULE: %s' % os.environ['DJANGO_SETTINGS_MODULE']from boosencms.weibo.analysis.models import WomWeiboSinafrom twango.manager import TwistedManagerfrom django.db.models.manager import Managerfrom twisted.internet import reactorfrom twisted.internet.defer import Deferredimport logginglogging.basicConfig(level = logging.INFO, format = "%(asctime)s %(levelname)s [%(filename)s:%(lineno)d]%(message)s")class TwistedWeiboSina(WomWeiboSina): objects = Manager() twisted = TwistedManager() class Meta: app_label = 'analysis' proxy = Truedef count_me(count): print "Count: %s" % countdef all(queryset): print 'All: %s' % querysetdef none(queryset): print 'None: %s' % querysetdef filter(queryset): print 'Filter: %s' % querysetdef callback(*args, **kwargs): TwistedWeiboSina.twisted.get_query_set().count(success_callback = count_me) TwistedWeiboSina.twisted.get_query_set().all(success_callback = all) TwistedWeiboSina.twisted.get_query_set().none(success_callback = none) TwistedWeiboSina.twisted.filter(createTime__gte = '2013-06-01', success_callback = filter)d = Deferred()d.addCallback(callback)d.callback(None)#callback()reactor.run()
twango源碼query.py的class TwistedQuerySet中需要加上filter的處理
def filter(self, **kwargs): return self._super_threaded('filter', **kwargs)