最近用python的正則表達式處理了一些文本數據,需要把結果寫到文件里面,但是由於文件比較大,所以運行起來花費的時間很長。但是打開任務管理器發現CPU只占用了25%,上網找了一下原因發現是由於一個叫GIL的存在,使得Python在同一時間只能運行一個線程,所以只占用了一個CPU,由於我的電腦是4核的,所以CPU利用率就是25%了。
既然多線程沒有什么用處,那就可以使用多進程來處理,畢竟多進程是可以不受GIL影響的。Python提供了一個multiprocessing的多進程庫,但是多進程也有一些問題,比如,如果進程都需要寫入同一個文件,那么就會出現多個進程爭用資源的問題,如果不解決,那就會使文件的內容順序雜亂。這就需要涉及到鎖了,但是加鎖一般會造成程序的執行速度下降,而且如果進程在多處需要向文件輸出,也不好把這些代碼整個都鎖起來,如果都鎖起來,那跟單進程還有什么區別。有一個解決辦法就是把向文件的輸出都整合到一塊去,在這一塊集中加個鎖,這樣問題就不大了。不過還有一種更加優雅的解決方式:使用multiprocessing庫的回調函數功能。
具體思路跟把文件輸出集中在一起也差不多,就是把進程需要寫入文件的內容作為返回值返回給惠和的回調函數,使用回調函數向文件中寫入內容。這樣做在windows下面還有一個好處,在windows環境下,python的多進程沒有像linux環境下的多進程一樣,linux環境下的multiprocessing庫是基於fork函數,父進程fork了一個子進程之后會把自己的資源,比如文件句柄都傳遞給子進程。但是在windows環境下沒有fork函數,所以如果你在父進程里打開了一個文件,在子進程中寫入,會出現ValueError: I/O operation on closed file這樣的錯誤,而且在windows環境下最好加入if __name__ == '__main__'這樣的判斷,以避免一些可能出現的RuntimeError或者死鎖。
下面是代碼:
from multiprocessing import Pool import time def mycallback(x): with open('123.txt', 'a+') as f: f.writelines(str(x)) def sayHi(num): return num if __name__ == '__main__': e1 = time.time() pool = Pool() for i in range(10): pool.apply_async(sayHi, (i,), callback=mycallback) pool.close() pool.join() e2 = time.time() print float(e2 - e1)