您好,登錄后才能下訂單哦!
Python的線程開發使用標準庫threading
Thread類
def __init__(self,group=None,target=None,name=None,args(),kwargs=None,*,daemon=None)
參數名 | 含義 |
target | 線程調用的對象,就是目標函數 |
name | 為線程起的名字 |
args | 為目標函數傳遞實參,元組 |
kwargs | 為目標函數傳遞關鍵字參數,字典 |
線程啟動
import threading def worker(): print("I'm working! wait a moment") t=threading.Thread(target=worker,name='worker') # 線程對象 t.start(). # 啟動
通過threading.Thread創建一個線程對象,target是目標函數,name可以指定自己喜歡的名字,線程的啟動需要借助start方法。線程執行函數,是因為線程中就是執行代碼的,最簡單的封裝就是函數,所以本質還是函數調用。
線程退出
Python沒有提供線程的退出方法,線程在下面的情況下時會退出
1. 線程函數內語句執行完畢
2. 線程函數中拋出未處理的異常
import threading import time def worker( ): count=0 while True: if(count>5): raise RuntimeError(count) time.sleep(1) print("I'm working!") count+=1 t=threading.Thread(target=worker,name="worker") t.start( ) print("===End===")
結果如圖所示:
Python的線程沒有優先級,沒有線程組的概念。
線程的傳參
import threading import time def add(x,y): print("{} + {} = {}".format(x,y,x+y)) t1=threading.Thread(target=add,name="add",args(4,5)) t1.start() time.sleep(2) t2=threading.Thread(target=add,name="add",kwargs={"x":4;"y":5}) t2.start() time.sleep(2) t3=threading.Thread(target=add,name="add",args=(4,),kwargs={"y":5}) t3.start()
線程傳參和函數傳參沒什么區別,本質上就是函數傳參。
threading的屬性和方法
名稱 | 含義 |
current_thread( ) | 返回當前線程對象 |
main_thread( ) | 返回主線程對象 |
active_count( ) | 當前處于alive狀態的線程個數 |
enumerate( ) | 返回所有活著的線程的列表,不包括已經終止的線程和未開始的線程 |
get_ident( ) | 返回當前線程的ID,非0整數 |
import threading import time def showthreadinfo(): print("currentthread = {}".format(threading.current_thread())) print("main thread = {}".format(threading.main_thread())) print("active count = {}".format(threading.active_count())) def worker(): count=0 showthreadinfo() while True: if(count>5): break time.sleep(1) count+=1 print("I'm working") t=threading.Thread(target=worker,name='worker') t.start() print('===End===')
結果如圖所示:
Thread實例的屬性和方法
名稱 | 含義 |
name | 只是一個名字,可以重新命名。getName(),setName()獲取,設置這個名詞 |
ident | 線程ID,它是非0整數,線程啟動后才會有ID,線程退出,仍可以訪問,可重復使用 |
is_alive() | 返回線程是否存活 |
多線程
一個進程中如果有多個線程,就是多線程,實現一種并發
import threading import time def worker(): count=0 while True: if(count>5): break time.sleep(0.5) count+=1 print("worker running") print(threading.current_thread().name,threading.current_thread().ident) t1=threading.Thread(name="worker1",target=worker) t2=threading.Thread(name="worker2",target=worker) t1.start() t2.start()
結果如圖所示:
可以看到worker1和worker2交替執行
daemon線程和non-daemon線程
進程靠線程執行代碼,至少有一個主線程,其它的線程都是工作線程。
父線程:如果線程A中啟動了一個線程B,A就是B的父線程。
子線程:B就是A的子線程。
Python中,構造線程的時候,可以設置daemon屬性,這個屬性必須在start方法之前設置好。線程daemon屬性,如果設定就是用戶的設置,否則就取當前線程的daemon值,主線程是non-daemon線程,即daemon=False
import time import threading def foo(): time.sleep(3) for i in range(10): print(i) t=threading.Thread(target=foo,daemon=False) t.start() print("Main Thread Exiting")
運行結果如圖所示:
主進程已經執行完畢,但是線程t依然在運行,主進程一直等待著線程t。當將Thread中daemon=False改為True時發現,主進程執行后立即會結束,根本不會等待t線程。
名稱 | 含義 |
daemon屬性 | 表示線程是否是daemon線程,這個值必須在start之前設置,否則引發RuntimeError異常 |
isDaemon | 是否是Daemon線程 |
setDaemon | 設置為daemon線程,必須在start方法之前設置 |
總結:
線程具有一個daemon屬性,可以設置主進程結束后是否等待其他的子線程,如果不設置,取默認值None。從主線程創建的所有線程的不設置daemon屬性,則默認daemon=False。
join方法
import time import threading def foo(n): for i in range(10): print(i) time.sleep(1) t1=threading.Thread(target=foo,args=(10,),daemon=True) t1.start() t1.join()
執行結果如圖所示:
根據上面講述的daemon線程,主進程設置的dameon=True,按理說主線程執行是根本不會去等待其它的線程,也就是不會打印這些數字,但是這里卻等待了子線程的運行打印出來了,這個就是join方法的作用。
join(timeout=None),是線程標準方法之一,一個線程中調用另一個線程的join方法,調用者將被阻塞,直到被調用的線程停止。一個線程可以被join多次,timeout是設置等待調用者多久,如果沒有設置,就一直等待,直到被調用者線程結束。
threading.local類
Python提供了threading.local類,將這個類實例化得到一個全局對象,但是不同的線程使用這個對象存儲的數據其他線程是不可見的。
import threading import time #全局對象 global_data=threading.local() def worker(): global_data=0 for i in range(100): time.sleep(0.001) global_data+=1 print(threading.current_thread(),global_data) for i in range(10): threading.Thread(target=worker).start()
運行結果如圖所示:
可以看到雖然是全局變量,但是這個變量在各個線程之間是獨立的,每個的計算結果不會對其他線程造成干擾。
怎么證明這個是在各個線程之間獨立的呢?
import threading TestData="abc" TestLocal=threading.local() TestLocal.x=123 print(TestData,type(TestLocal),TestLocal.x) def worker(): print(TestData) print(TestLocal) print(TestLocal.x) worker() print("=====") threading.Thread(target=worker).start()
可以看下運行結果
在子線程里面打印TestLocal.x時候出錯,顯示AttributeError: "_thread._local_" object has no attribute 'x',這是因為TestLocal.x我們是在主線程里面定義的,啟動一個子線程我們并沒有這個屬性,所以報錯,從而說明threading.local定義的變量,在各個線程之間是獨立的,不能跨線程。
threading.local類構建了一個大字典,其元素是每一線程實例的地址為key和線程對象引用線程單獨的字典的映射:
{id(Thread) -> (ref(Thread), thread-local dict)}
定時器Timer
threading.Timer繼承自Thread,用來定義多久執行一個函數。
class threading.Timer(interval,function,args=None,kwargs=None)
start方法執行之后,Timer對象會等待interval時間,然后開始執行function函數,如果在等待階段,使用了cancal方法,就會跳過執行而結束
import threading import time def worker(): print("in worker") time.sleep(2) t=threading.Timer(5,worker) t.start() print(threading.enumerate()) t.cancel() time.sleep(1) print(threading.enumerate())
可以看到,延遲5s執行worker線程,然后主線程繼續執行,打印存活的線程,就是主線程和worker線程,然后執行cancel,子線程就會被取消執行,sleep 1s后打印存活的線程就只有主線程。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。