從一次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更通用
  • 學習業界著名開源軟件設計思想
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章