在上一篇中對代碼進行了優化,離需求進了一步,但還是很大距離,代碼進一步優化我也不知道怎么辦了,不會高深的算法。只能從改進系統架構考慮。
方案3: 改變系統架構
在開始多進程之前,先簡單說明一下python GIL, 之前自己對他也有些誤解。因為python GIL的機制存在,同時運行的線程只有一個,但這個線程在不同時刻可以運行在不同的核上,這個調度是由
操作系統完成的,如果你寫個死循環,開的線程足夠多,是可以把整個系統的CPU消耗干凈的,此時你在
Linux下通過top可以看到,us 占用的CPU不大,但sy占用的CPU會很大,CPU主要消耗在系統調度上了。下面是
測試代碼,大家可以試試。
import threading class MultipleThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): while 1: print "here" for i in xrange(100): multiple_thread=MultipleThread() multiple_thread.start() multiple_thread.join() |
既然因為GIL的存在,同時只能運行一個線程,那多線程可以提高效率,當然可以!開個3-4個線程可以明顯的提高性能,大概能提高個2-3倍左右吧,但繼續增加線程就是副作用了。
系統多線程的系統架構:
發送和接受都不存在瓶頸,主要瓶頸在在紅線部分,decode和 encode部分。多線程改成多進程比較簡單,
工作量不大,只要把需要多進程共享的信息,由Queue改成multiprocessing.Queue()就可以了,把繼承的DiameterMsgParser(threading.Thread)改成DiameterMsgParser(multiprocessing.Process),有個比較麻煩的是log的輸出,python自帶的logging模塊在多進程下寫同一個文件會引起混亂。這個在后面單獨說明。
import multiprocessing import logging class Worker(multiprocessing.Process): def __init__(self,mp_name,input_queue): multiprocessing.Process.__init__(self,name=mp_name) self.input_queue=input_queue def run(self): for i in xrange(100): self.input_queue.put_nowait(i) logging.debug(" test "+str(i)) |
多線程改成多進程后,在sunfire 4170 (16 core , 2.4G ) 上能支持到5000 meesages (雙向), CPU占有率 30-40%,用的是標準的python2.7,因為在solaris上沒安裝成功pypy,所以在此機器上,我沒有測試pypy對性能影響多大。但我在一個2核的linux機器上測試python和 pypy,在多進程的情況下的效率,pypy對效率的提升沒有達到倍數的級別,沒找到什么原因, 后面有CPU核數比較多的機器再測試下。