1. 程式人生 > >從一次python程式的效能優化說開去

從一次python程式的效能優化說開去

一門程式語言入門是容易的,至少大家都知道從hello world開始。但這次效能優化的經歷告訴我,“換語言”這件事是有門檻的。

這次效能優化是針對資料入庫流程中的一個環節(brief)做的。

我們常說解決問題重要,發現問題更重要。沒錯,這次發現問題就佔用了我較長時間。brief部署在X平臺上,通過增加日誌,我發現brief耗時較長的部分發生在平臺內部,接下來主要工作就是找X平臺的負責同學溝通了。X平臺已經升級到第三代,而我們還停留在第一代,版本低不要緊,關鍵是問題比較多,對方投入人力少,只找到對應有效的負責同學就費了很大勁(現在知道與時俱進是多麼重要了,^-^!)

經過X平臺同學的不懈努力,最終定位為brief的吞吐能力不行,導致整體耗時增加。Ok,掃一眼程式碼,看brief是單執行緒的,既然吞吐不行,那就改成多執行緒吧。等等,這就定了方案了?

方法論有問題。需要這麼小題大做麼?吞吐不行,為啥不先看看單執行緒慢在哪裡呢?C++、java都有對應的profile工具,python估計也有吧。一搜,果然,不僅有,而且使用起來更簡單,是python自帶的工具。

python -m profile /path/to/your.py

執行結束,程式熱點立現。

好吧。確實存在很多CPU計算,不太好優化。轉多執行緒吧。儘管我們最終還是要朝著多執行緒的方向去思考,但是思路不能斷,這有助於培養我們的方法論意識。

多執行緒能解決問題麼? 不能!python直譯器內部有一把全域性鎖GIL(Global interpreter Lock),對於計算密集型程式來說,可認為還是單執行緒執行,並不能提高程式吞吐。好吧,我一開始並不知道python的多執行緒是偽多執行緒,這就涉及到語言設計層面的問題,對於我這種只瞭解hello world的python程式設計師,顯然發現不了這樣的問題。在現在小學生都要普及python教育的時代,我是out了,要加強學習啊。

言歸正傳,多執行緒解決不了怎麼辦?增加併發還是可以使用多程序,從此踏入了不歸路。知道python NB的我堅信python肯定有多程序支援,hello world的思想讓我在百度很快找到了python多程序demo。把demo搬到brief,執行brief,程式無法退出,CTRL + C後發現,程式在疑似鎖等待的位置拋異常了。多程序的生產者消費者模型不好寫啊,multiprocessing.Queue竟然沒有判斷queue關閉的介面,只能自己實現了一套:

queue_closed = multiprocessing.Value('i', 0)

def produce(q, cnt, value, queue_closed):
    while cnt:
        q.put(value)
        cnt = cnt - 1   
    q.close()
    queue_closed.value = 1
    q.join()

def consume(q, queue_closed):
    while True:
        try:
            if queue_closed.value == 1 and q.qsize() == 0:
                break
            value = q.get(timeout=0.01)
            process(value, output_queue)
            q.task_done()
        except Empty:
            logging.warning("get queue item timeout")

死鎖問題解決了,利用多程序確實提高brief的吞吐,但另外一個問題來了:日誌怎麼打?logging支援多執行緒,但不支援多程序。又是一番搜尋,找到幾個解決方案,multiprocessing_logging,ConcurrentLogHandler,試了一下又出現一直死鎖的問題了,被死鎖搞得焦頭爛額,這次算是比較常見的問題了:多執行緒環境下fork,即多程序多執行緒,fork子程序時把父程序持有的鎖也複製了,導致父程序釋放鎖時,子程序並不能感知這個狀態,進而死鎖,解決方案先fork子程序,後啟動執行緒。最終,通過ConcurrentLogHandler解決日誌問題,ConcurrentLogHandler使用到了檔案鎖,對效能要求很高的程式慎用(當然,如果實在很高,你該選用C++了)。業界有名的軟體nginx採用的是單執行緒多程序的架構,可以學習一下她的日誌列印機制。

至此,brief效能優化告一段落。總結一下:

  • 學習一門新的語言,從更高層次去了解它的設計思想或許是一種更有效的學習方式,畢竟思想比hello world更通用
  • 學習業界著名開源軟體設計思想