線程的有兩種使用方法,,一種是在函數(shù)使用,一種是放在類中使用。 1,,在函數(shù)中使用多線程語(yǔ)法如下: | thread.start_new_thread(function, args[, kwargs] ) | 參數(shù)說(shuō)明: | function - 線程函數(shù)。 args - 傳遞給線程函數(shù)的參數(shù),必須是個(gè)tuple類型,。 kwargs - 可選參數(shù),。 | 下面是一個(gè)例子: | def run(num): print 'hi , i am a thread.', num def main(): threads = [] for i in range(5): t = threading.Thread(target=run, args=(i,)) threads.append(t) t.start() for t in threads: t.join() if __name__ == '__main__': print 'start -->' main() print 'go here -->' | 運(yùn)行結(jié)果: | start --> hi , i am a thread. 0 hi , i am a thread. 1 hi , i am a thread. 2 hi , i am a thread. 3 hi , i am a thread. 4 go here --> | 2,在類中多使用線程下面是在類中使用線程的示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class MyThread(threading.Thread): def __init__(self,num): self.num = num super(MyThread, self).__init__() def run(self): print 'i am a thread,',self.num time.sleep(1) def main(): threads = [] for i in range(5): t = MyThread(i) threads.append(t) t.start() for t in threads: t.join() if __name__ == '__main__': print 'start -->' main() print 'go here --> | - run(),,需要重寫(xiě),,編寫(xiě)代碼實(shí)現(xiàn)所需要的功能。
- getName(),,獲得線程對(duì)象名稱
- setName(),,設(shè)置線程對(duì)象名稱
- start(),啟動(dòng)線程
- join([timeout]),,等待另一線程結(jié)束后再運(yùn)行,。
- setDaemon(bool),設(shè)置子線程是否隨主線程一起結(jié)束,,必須在
start() 之前調(diào)用,,默認(rèn)為False 。 - isDaemon(),,判斷線程是否隨主線程一起結(jié)束,。
- isAlive(),檢查線程是否在運(yùn)行中,。
join 方法的作用是阻塞主進(jìn)程(無(wú)法執(zhí)行join 以后的語(yǔ)句),,主線程等待這個(gè)線程結(jié)束后,才可以執(zhí)行下一條指令,。多線程多join 的情況下,,依次執(zhí)行各線程的join 方法,前頭一個(gè)結(jié)束了才能執(zhí)行后面一個(gè),。無(wú)參數(shù),,則等待到該線程結(jié)束,才開(kāi)始執(zhí)行下一個(gè)線程的join ,。設(shè)置參數(shù)后,,則等待該線程這么長(zhǎng)時(shí)間就不管它了(而該線程并沒(méi)有結(jié)束)。不管的意思就是可以執(zhí)行后面的主進(jìn)程了,。
3,,線程同步與互斥鎖線程之所以比進(jìn)程輕量,其中一個(gè)原因就是他們共享內(nèi)存,。也就是各個(gè)線程可以平等的訪問(wèn)內(nèi)存的數(shù)據(jù),,如果在短時(shí)間“同時(shí)并行”讀取修改內(nèi)存的數(shù)據(jù),,很可能造成數(shù)據(jù)不同步。例如下面的例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var = 0 class IncreThread(Thread): def run(self): global var print 'before,var is ',var var += 1 print 'after,var is ',var def use_incre_thread(): threads = [] for i in range(50): t = IncreThread() threads.append(t) t.start() for t in threads: t.join() print 'After 10 times,var is ',var if __name__ == '__main__': use_incre_thread() | 有一個(gè)全局變量var ,,五十個(gè)線程,,每個(gè)線程對(duì)var 變量進(jìn)行加 1 運(yùn)算,但是當(dāng)你多運(yùn)行幾次后,,發(fā)現(xiàn)并不是每次的運(yùn)行結(jié)果都是 50,,為什么呢? 在var 是 10 的時(shí)候,,線程t1 讀取了var ,,這個(gè)時(shí)刻cpu 將控制權(quán)給了另一個(gè)線程t2 。t2 線程讀到的var 也是 10,,t1 和t2 都把var 加到 11,,當(dāng)時(shí)我們期望的是t1 t2 兩個(gè)線程使var + 2 變成 12。在這里就有了資源競(jìng)爭(zhēng),,相同的情況也可能發(fā)生在其它的線程間,,所以出現(xiàn)了最后的結(jié)果小于 50 的情況。
為了避免線程不同步造成數(shù)據(jù)不同步,,可以對(duì)資源進(jìn)行加鎖,。也就是訪問(wèn)資源的線程需要獲得鎖,才能訪問(wèn),。threading 模塊提供了一個(gè) Lock 功能,,修改代碼如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var = 0 lock = Lock() #創(chuàng)建鎖 class IncreThread(Thread): def run(self): global var lock.acquire() #獲取鎖 print 'before,var is ',var var += 1 print 'after,var is ',var lock.release() #釋放鎖 def use_incre_thread(): threads = [] for i in range(50): t = IncreThread() threads.append(t) t.start() for t in threads: t.join() print 'After 10 times,var is ',var if __name__ == '__main__': use_incre_thread() | 雖然線程可以共享內(nèi)存,,但是一個(gè)線程不能影響其他線程內(nèi)的變量(非全局變量),。 4,死鎖在線程間共享多個(gè)資源的時(shí)候,,如果兩個(gè)線程分別占有一部分資源并且同時(shí)等待對(duì)方的資源,,就會(huì)造成死鎖。盡管死鎖很少發(fā)生,,但一旦發(fā)生就會(huì)造成應(yīng)用的停止響應(yīng),。下面是一個(gè)死鎖的例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | mutex_a = Lock() mutex_b = Lock() class MyThread(Thread): def task_b(self): if mutex_a.acquire(): print 'thread get a mutex_a',self.name time.sleep(1) if mutex_b.acquire(): print 'get a mutex_b',self.name mutex_b.release() mutex_a.release() def task_a(self): if mutex_b.acquire(): print 'thread get a mutex_b',self.name time.sleep(1) if mutex_a.acquire(): print 'get a mutex_a',self.name mutex_a.release() mutex_b.release() def run(self): self.task_a() self.task_b() if __name__ == '__main__': threads = [MyThread() for i in range(2)] print threads for t in threads: t.start() | 線程需要執(zhí)行兩個(gè)任務(wù),兩個(gè)任務(wù)都需要獲取鎖,,當(dāng)兩個(gè)任務(wù)得到鎖后,,就需要等另外鎖釋放。 5,,可重入鎖為了支持在同一線程中多次請(qǐng)求同一資源,,python 提供了可重入鎖(RLock )。RLock 內(nèi)部維護(hù)著一個(gè)Lock 和一個(gè)counter 變量,,counter 記錄了acquire 的次數(shù),,從而使得資源可以被多次require ,。直到一個(gè)線程所有的acquire 都被release ,其他的線程才能獲得資源,。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | mutex = threading.RLock() class MyThread(threading.Thread): def run(self): if mutex.acquire(1): print 'threading gte mutex:',self.name time.sleep(1) mutex.acquire() mutex.release() mutex.release() def main(): print 'start main threading:' threads = [MyThread() for i in range(2)] for t in threads: t.start() for t in threads: t.join() print 'end main threading.' if __name__ == '__main__': main() | 6,,后臺(tái)線程使用多線程默認(rèn)情況下,當(dāng)主線程退出之后,,即使子線程沒(méi)有 join ,,子線程也依然會(huì)繼續(xù)執(zhí)行。如果希望主線程退出后,,其子線程也退出而不再執(zhí)行,,則需要設(shè)置子線程為后臺(tái)線程。python 提供了setDaemon 方法,,將子線程與主線程進(jìn)行綁定,,當(dāng)主線程退出時(shí)子線程的生命也隨之結(jié)束。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class MyThread(threading.Thread): def run(self): wait_time = random.randrange(1, 10) print 'thread %s will wait %s s' %(self.name, wait_time) time.sleep(wait_time) time.sleep(30) print 'thread %s finished.' % self.name def main(): print 'start thread:' for i in range(3): t = MyThread() t.setDaemon(1) t.start() print 'end thread.' if __name__ == '__main__': main() | 運(yùn)行結(jié)果: | start thread: thread Thread-1 will wait 9 s thread Thread-2 will wait 1 s thread Thread-3 will wait 7 s end thread. | 本來(lái)子線程需要等待幾秒才能結(jié)束,,但是主線程提前結(jié)束了,,所以子線程也隨主線程結(jié)束了。
|