前言
這兩天為了做一個小項目,研究了一下python的並發編程,所謂並發無非多線程和多進程,最初找到的是threading模塊,因為印象中線程“輕量...”,“切換快...”,“可共享進程資源...”等等,但是沒想到這裡水很深,進而找到了更好的替代品multiprocessing模塊。下面會講一些使用中的經驗。
後面出現的代碼都在Ubuntu10.04 + python2.6.5的環境下測試通過。
一、使用threading模塊創建線程
1、三種線程創建方式
(1)傳入一個函數
這種方式是最基本的,即調用threading中的Thread類的構造函數,然後指定參數target=func,再使用返回的Thread的實例調用start()方法,即開始運行該線程,該線程將執行函數func,當然,如果func需要參數,可以在Thread的構造函數中傳入參數args=(...)。示例代碼如下:
#!/usr/bin/python
#-*-coding:utf-8-*-
import threading
#用於線程執行的函數
def counter(n):
cnt = 0;
for i in xrange(n):
for j in xrange(i):
cnt += j;
print cnt;
if __name__ == '__main__':
#初始化一個線程對象,傳入函數counter,及其參數1000
th = threading.Thread(target=counter, args=(1000,));
#啟動線程
th.start();
#主線程阻塞等待子線程結束
th.join();
這個例子關鍵的一句是apply(self.func, self.args); 這裡使用初始化時傳入的函數對象及其參數來進行一次調用。
(3)繼承Thread類
這種方式通過繼承Thread類,並重載其run方法,來實現自定義的線程行為,示例代碼如下:
#!/usr/bin/python
#-*-coding:utf-8-*-
import threading, time, random
def counter():
cnt = 0;
for i in xrange(10000):
for j in xrange(i):
cnt += j;
class SubThread(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self, name=name);
def run(self):
i = 0;
while i < 4:
print self.name,'counting...\n';
counter();
print self.name,'finish\n';
i += 1;
if __name__ == '__main__':
th = SubThread('thread-1');
th.start();
th.join();
print 'all done';
這個例子定義了一個SubThread類,它繼承了Thread類,並重載了run方法,在方法中調用counter4次並打印一些信息,可以看到這種方式比較直觀。在構造函數中要記得先調用父類的構造函數進行初始化。
2、python多線程的限制
python多線程有個討厭的限制,全局解釋器鎖(global interpreter lock),這個鎖的意思是任一時間只能有一個線程使用解釋器,跟單cpu跑多個程序一個意思,大家都是輪著用的,這叫“並發”,不是“並行”。手冊上的解釋是為了保證對象模型的正確性!這個鎖造成的困擾是如果有一個計算密集型的線程占著cpu,其他的線程都得等著....,試想你的多個線程中有這麼一個線程,得多悲劇,多線程生生被搞成串行;當然這個模塊也不是毫無用處,手冊上又說了:當用於IO密集型任務時,IO期間線程會釋放解釋器,這樣別的線程就有機會使用解釋器了!所以是否使用這個模塊需要考慮面對的任務類型。