#常規寫法
import threading import time def sayhi(num): # 定義每一個線程要運行的函數 print("running on number:%s" % num) time.sleep(3) if __name__ == '__main__': t1 = threading.Thread(target=sayhi, args=(1,)) # 生成一個線程實例 t2 = threading.Thread(target=sayhi, args=(2,)) # 生成另外一個線程實例 t1.start() # 啓動線程 t2.start() # 啓動另外一個線程 print(t1.getName()) # 獲取線程名 print(t2.getName())
自定義線程類 import threading import time class MyThread(threading.Thread): def __init__(self, num): threading.Thread.__init__(self) self.num = num def run(self): # 定義每一個線程要運行的函數 print("running on number:%s" % self.num) time.sleep(3) if __name__ == '__main__': t1 = MyThread(1) t2 = MyThread(2) t1.start() t2.start()
import threading import time def sayhi(num): # 定義每一個線程要運行的函數 print("running on number:%s" % num) time.sleep(3) start_time=time.time() if __name__ == '__main__': for i in range(50): ###多線程 t = threading.Thread(target=sayhi, args=(i,)) # 生成一個線程實例 t.start() print (start_time-time.time()) ####打印時間 此時打印結果時間爲0.0000幾秒,是由於程序在執行完多線程時繼續往下執行,而不會等待線程執行完在打印時間,因此打印出來的時間並非多線程執行的時間
join() 線程執行後,主線程會等待全部線程執行完畢後繼續往下走,下面實例介紹計算多線程執行時間 import threading import time def sayhi(num): # 定義每一個線程要運行的函數 print("running on number:%s" % num) time.sleep(3) start_time=time.time() threads = [] ####定義一個列表,將全部的線程加進去 if __name__ == '__main__': for i in range(50): ###多線程 t = threading.Thread(target=sayhi, args=(i,)) # 生成一個線程實例 t.start() threads.append(t) ####將每一個線程添加到列表 for t in threads: ###循環整個列表,進行join(每一個線程join完成後主線程纔會繼續往下走) t.join() ###等待全部線程執行結束,至關於單線程 print (start_time-time.time())
示例二python
#!/usr/bin/env python #-*-coding:utf-8-*- import threading from time import ctime,sleep import time def music(func): for i in range(2): print ("Begin listening to %s. %s" %(func,ctime())) sleep(1) print("end listening %s"%ctime()) def move(func): for i in range(2): print ("Begin watching at the %s! %s" %(func,ctime())) sleep(5) print('end watching %s'%ctime()) threads = [] t1 = threading.Thread(target=music,args=('music',)) threads.append(t1) t2 = threading.Thread(target=move,args=('movie',)) threads.append(t2) if __name__ == '__main__': for t in threads: t.start() print ("all over %s" %ctime())
主線程不會等待守護線程結束在退出,會等待非守護線程執行完畢才退出多線程
將線程設置爲Daemon線程,它作爲程序主線程的守護線程,當主線程退出時,線程也會退出,由守護線程動的其它子線程會同時退出,不論是否執行完任務併發
因爲線程之間是進行隨機調度,而且每一個線程可能只執行n條執行以後,當多個線程同時修改同一條數據時可能會出現髒數據,因此,出現了線程鎖 - 即同一時刻容許一個線程執行操做app
###沒有加鎖時 import threading import time,sys def addNum(): global num # 在每一個線程中都獲取這個全局變量 print('--get num:', num) time.sleep(1) num -= 1 # 對此公共變量進行-1操做 num = 100 # 設定一個共享變量 thread_list = [] for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: # 等待全部線程執行完畢 t.join() print('final num:', num) 說明: 正常來說,這個num結果應該是0, 但在python 2.7上多運行幾回,會發現,最後打印出來的num結果不老是0,爲何每次運行的結果不同呢?
假設你有A,B兩個線程,此時都 要對num 進行減1操做, 因爲2個線程是併發同時運行的,因此2個線程頗有可能同時拿走了num=100這個初始變量交給cpu去運算,當A線程去處完的結果是99,但此時B線程運算完的結果也是99,兩個線程同時CPU運算的結果再賦值給num變量後,結果就都是99。那怎麼辦呢? 很簡單,每一個線程在要修改公共數據時,爲了不本身在還沒改完的時候別人也來修改此數據,能夠給這個數據加一把鎖, 這樣其它線程想修改此數據時就必須等待你修改完畢並把鎖釋放掉後才能再訪問此數據。 加鎖版本: import threading import time gl_num = 0 lock = threading.RLock() ## 生成全局鎖 def Func(): lock.acquire() #修改數據前加鎖 global gl_num gl_num += 1 time.sleep(1) print(gl_num) lock.release() ###修改後釋放 for i in range(10): t = threading.Thread(target=Func) t.start()
遞歸鎖(即大鎖之下在加小鎖)dom
import threading, time
def run1():
print("grab the first part data")
lock.acquire()
global num
num += 1
lock.release()
return num
def run2():
print("grab the second part data")
lock.acquire()
global num2
num2 += 1
lock.release()
return num2
def run3():
lock.acquire()
res = run1()
print('--------between run1 and run2-----')
res2 = run2()
lock.release()
print(res, res2)
if __name__ == '__main__':
num, num2 = 0, 0
lock = threading.RLock() for i in range(10): t = threading.Thread(target=run3) t.start() while threading.active_count() != 1: print(threading.active_count())
else:
print('----all threads done---')
print(num, num2)
有一類線程須要知足條件以後纔可以繼續執行,Python提供了threading.Condition 對象用於條件變量線程的支持,它除了能提供RLock()或Lock()的方法外,還提供了 wait()、notify()、notifyAll()方法。ide
lock_con=threading.Condition([Lock/Rlock]): 鎖是可選選項,不傳人鎖,對象自動建立一個RLock()。
wait():條件不知足時調用,線程會釋放鎖並進入等待阻塞; notify():條件創造後調用,通知等待池激活一個線程; notifyAll():條件創造後調用,通知等待池激活全部線程。
示例函數
import threading,time from random import randint class Producer(threading.Thread): def run(self): global L while True: val=randint(0,100) print('生產者',self.name,":Append"+str(val),L) if lock_con.acquire(): L.append(val) lock_con.notify() lock_con.release() time.sleep(3) class Consumer(threading.Thread): def run(self): global L while True: lock_con.acquire() if len(L)==0: lock_con.wait() print('消費者',self.name,":Delete"+str(L[0]),L) del L[0] lock_con.release() time.sleep(0.25) if __name__=="__main__": L=[] lock_con=threading.Condition() threads=[] for i in range(5): threads.append(Producer()) threads.append(Consumer()) for t in threads: t.start() for t in threads: t.join()
互斥鎖,同時只容許一個線程更改數據,而Semaphore是同時容許必定數量的線程更改數據 ,好比兩個水龍頭,那最多隻容許2我的同時使用,後面的人只能等有人用完後才能使用。ui
信號量用來控制線程併發數的,BoundedSemaphore或Semaphore管理一個內置的計數 器,每當調用acquire()時-1,調用release()時+1。spa
計數器不能小於0,當計數器爲 0時,acquire()將阻塞線程至同步鎖定狀態,直到其餘線程調用release()。(相似於停車位的概念)線程
BoundedSemaphore與Semaphore的惟一區別在於前者將在調用release()時檢查計數 器的值是否超過了計數器的初始值,若是超過了將拋出一個異常。
實例:
import threading, time def run(n): semaphore.acquire() time.sleep(1) print("run the thread: %s" % n) semaphore.release() if __name__ == '__main__': num = 0 semaphore = threading.BoundedSemaphore(5) # 最多容許5個線程同時運行,有一個執行完畢後會執行另外一個 for i in range(20): t = threading.Thread(target=run, args=(i,)) t.start()