標籤:otto 線程的狀態 空間 面向 主線程 join() ges inline dem
線程基礎
什麼是線程(thread)
線程是CPU調度能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流程[換言之,線程就是一堆指令集合],一個進程中可以並發多個線程,每條線程並存執行不同的任務
線程的執行特性
線程只有 3 個基本狀態:就緒,執行,阻塞。
線程存在 5 種基本操作來切換線程的狀態:派生,阻塞,啟用,調度,結束。
什麼是進程(Process)
進程,是並發執行的程式在執行過程中作業系統分配和管理資源的基本單位,是一個動態概念,竟爭電腦系統資源的基本單位。每一個進程都有一個自己的地址空間,即進程空間或(虛空間)。進程空間的大小 只與處理機的位元有關
進程開闢子進程,子進程完全Copy父進程,比如父進程佔用20M,子進程也佔用20M,所以開進程比開線程更消耗資源
線程與進程的區別
線程共用建立它的進程的地址空間; 進程有自己的地址空間。
線程可以直接存取其進程的資料區段; 進程擁有其父進程的資料區段的自己的副本。
線程可以直接與其進程的其他線程通訊; 進程必須使用處理序間通訊與兄弟進程進行通訊。
新線程很容易建立; 新線程需要重複父線程。比如父進程佔用20M,子進程也佔用20M,所以開進程比開線程更消耗資源
線程之間可以相互操作,進程之間不可以
對主線程的更改(取消,優先順序更改等)可能會影響進程的其他子線程線程; 父進程的更改不會影響子進程。
問:線程執行快還是執行進程快?[陷阱題]
答: 一樣快,跑的內容是一樣的
Python可以建立多進程,不嚴格來說因為有GIL,Python沒有多線程,但是可以利用多進程來解決[多進程下不能實現資料共用,可以通過其他解決,協程,堆等方案]實現CPU多核的利用
如果在py裡面,任務是IO密集型[不是一直調用CPU執行任務,會有sleep等IO阻塞],多線程,如果計算密集型,可以考慮C開發
線程建立
線程的建立:
1. 直接調用,threading.Thread(target=sayhi,args=(1,)
2. 繼承式調用:
直接調用:
import timeimport threadingbegin=time.time()def bar(n): print(‘bar%s‘%n) time.sleep(3)def foo(n): print(‘foo%s‘ %n) time.sleep(2)t1 = threading.Thread(target=bar, args=(1,)) # 建立t1線程對象t2 = threading.Thread(target=foo, args=(2,)) # 建立t2線程對象t1.start() # 線程啟動,開始搶佔CPU資源t2.start() # 線程啟動,開始搶佔CPU資源end=time.time()t1.join() # 線程阻塞,執行完天t1後執行主線程t2.join() # 線程阻塞,執行完天t2後執行主線程end2 = time.time()print(‘此時有3個線程,主線程,t1線程, t2線程‘)print(end-begin)print(end2-begin)
繼承式調用:
import threadingimport timeclass 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()
線程常用方法
Thread.join():在子線程完成運行之前,這個子線程的父線程將一直被阻塞。
import threadingfrom time import ctime,sleepimport timedef music(func): for i in range(2): print ("Begin listening to %s. %s" %(func,ctime())) sleep(4) 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=(‘七裡香‘,))threads.append(t1)t2 = threading.Thread(target=move,args=(‘阿甘正傳‘,))threads.append(t2)if __name__ == ‘__main__‘: for t in threads: t.start() # t1.start(). t2.start() # t.join() # 串列執行,t1.start()後,進入t1.join()等到t1執行完後在執行t2 # t.join() # Python中預設取最後一個for迴圈的t2,等價於t2.join() # t1.join() # 主線程的print()會在第8秒出,最後列印end movies t.join() # t2.join(),t2執行end後程式結束 print ("all over %s" %ctime())
setDemaon(True):
將線程聲明為守護線程,必須在start() 方法調用之前設定, 如果不設定為守護線程程式會被無限掛起。這個方法基本和join是相反的。當我們在程式運行中,執行一個主線程,如果主線程又建立一個子線程,主線程和子線程 就分兵兩路,分別運行,那麼當主線程完成想退出時,會檢驗子線程是否完成。如果子線程未完成,則主線程會等待子線程完成後再退出。但是有時候我們需要的是 只要主線程完成了,不管子線程是否完成,都要和主線程一起退出,這時就可以 用setDaemon(True)
import threadingfrom time import ctime,sleepimport timedef music(func): for i in range(2): print ("Begin listening to %s. %s" %(func,ctime())) sleep(4) 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=(‘七裡香‘,))threads.append(t1)t2 = threading.Thread(target=move,args=(‘阿甘正傳‘,))threads.append(t2)if __name__ == ‘__main__‘: # t2.setDaemon(True) # 執行t1後就結束程式,也就是說不執行 print(‘end watching %s‘%ctime()) for t in threads: t.setDaemon(True) # 將線程聲明為守護線程,必須在start() 方法調用之前設定 t.start() # t1.start(). t2.start() print ("all over %s" %ctime())
Thread提供線程的方法
thread 模組提供的其他方法: threading.currentThread(): 返回當前的線程變數。 threading.enumerate(): 返回一個包含正在啟動並執行線程的list。正在運行指線程啟動後、結束前,不包括啟動前和終止後的線程。 threading.activeCount(): 返回正在啟動並執行線程數量,與len(threading.enumerate())有相同的結果。 除了使用方法外,線程模組同樣提供了Thread類來處理線程,Thread類提供了以下方法: run(): 用以表示線程活動的方法。 start():啟動線程活動。 join([time]): 等待至線程中止。這阻塞調用線程直至線程的join() 方法被調用中止-正常退出或者拋出未處理的異常-或者是可選的逾時發生。 isAlive(): 返回線程是否活動的。 getName(): 返回線程名。 setName(): 設定線程名。
python 的GIL(
Global Interpreter Lock
)
解譯器原因: 由於Cpython解釋的原因,同一時刻只能解譯器只能調用一個線程,可以理解Python沒有多線程
CPython實現細節:在CPython中,由於全域解譯器鎖定,只有一個線程可以一次執行Python代碼(即使某些面向效能的庫可能會克服此限制)。 如果您希望您的應用程式更好地利用多核電腦的計算資源,建議您使用多處理。 但是,如果要同時運行多個I / O密集型任務的話,線程仍然是一個合適的模型。
Python學習---線程學習 1220