內容簡述:
? ? ?一:初始線程和進程
? ? ?二:進程和線程的區別
? ? ?三:線程的調用方式
? ? ?四:線程安全與線程鎖
? ? ?五:同步和異步
? ? ?六:隊列
? ? ?七:生產者和消費者模型
? ? ?八:協程
一:初始線程,進程
? ? ? ?看圖說話:
? ????多任務: 操作系統可同時運行多個任務,每一個程序內存都是獨立的? ? ?
????????一邊瀏覽器上網,一邊看電影,一邊打開WORD至少3個任務在運行還有????? 后臺運行的任務?? 概述:對于操作系統來說,一個任務就是一個進程.例如:打開一個瀏覽器就是啟動一個瀏覽器進程,打開兩word就啟動了兩個word進程,有的進程還不止同時干一件事,比如Word,它可以同時進行打字、拼寫檢查、縮進等事情。在一個進程內部,要同時干多件事,就需要同時運行多個“子任務”,我們把進程內的這些“子任務”稱為線程(Thread)
? ? ? 進程
???????(Process)是一個正在執行的程序,以一個整體的形式暴露給操作系統管理,里面包含對各種資源的調用,內存的管理,網絡接口的調用等。。。對各種資源管理的集合。所有在同一個進程里的線程是共享同一塊內存空間的
? ? ? 線程
? ??????是進程中一個獨立的控制單元,它被包含在進程之中。是操作系統最小的調度單位, 是一串指令的集合。 一個進程中至少有一個線程,一個進程中可以并發多個線程,每條線程并行執行不同的任務
? ? ? 備注:
? ? ? ? 進程要操作CPU,必須先創建一個線程,一個進程中至少有一個線程
二:進程和線程的區別
1-Threads share the address space of the process that created it; processes have their own address space.
線程共享創建它的進程的內存空間;進程有自己的內存空間是獨立的
2-Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
線程可以直接訪問進程的數據;進程擁有父進程的數據的副本
3-Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
同一個進程的線程之間可以互相訪問;兩個進程想通信,須通過一個中間代理來實現
4-New threads are easily created; new processes require duplication of the parent process.
創建新線程很容易;創建新進程需要復制父進程。
5-Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
一個線程可以控制和操作同一進程里的其他線程;進程只能操作子進程
6-Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.
對主線程的更改(取消、優先級更改等)可能會影響進程中其他線程的行為;對父進程的更改不會影響子進程。
三:線程的調用方式
? ??????1-函數式調用
? ??????2-繼承式調用
四:線程安全與線程鎖
? ??????多線程中,所有變量都由所有線程共享。所以任何一個變量都可以被任意一個線程修改,因此,線程之間共享數據最大的危險在于多個線程同時修改一個變量,造成數據混亂問題。
? ? ????解決方式:線程鎖(互斥鎖)
? ?互斥鎖
? ? ? ??當多個線程幾乎同時修改某一個共享數據的時候,需要進行同步控制
????????線程同步能夠保證多個線程安全訪問競爭資源,最簡單的同步機制是引入互斥鎖。
????????互斥鎖為資源引入一個狀態:鎖定/非鎖定。
????????某個線程要更改共享數據時,先將其鎖定,此時資源的狀態為“鎖定”,其他線程不能更改;直到該線程釋放資源,將資源的狀態變成“非鎖定”,其他的線程才能再次鎖定該資源。互斥鎖保證了每次只有一個線程進行寫入操作,從而保證了多線程情況下數據的正確性。
? ??????hreading模塊中定義了Lock類,可以方便的處理鎖定:
????????lock= threading.Lock()??????#創建鎖
? ? ????lock.acquire([blocking])?????#鎖定
? ? ????lock.release()? ? ? ? ? ? ? ? ? ?#釋放
其中,鎖定方法acquire可以有一個blocking參數。
如果設定blocking為True,則當前線程會堵塞,直到獲取到這個鎖為止(默認)
如果設定blocking為False,則當前線程不會堵塞
上鎖解鎖過程
當一個線程調用鎖的acquire()方法獲得鎖時,鎖就進入“locked”狀態。每次只有一個線程可以獲得鎖。如果此時另一個線程試圖獲得這個鎖,該線程就會變為“blocked”狀態,稱為“阻塞”,直到擁有鎖的線程調用鎖的release()方法釋放鎖之后,鎖進入“unlocked”狀態。線程調度程序從處于同步阻塞狀態的線程中選擇一個來獲得鎖,并使得該線程進入運行(running)狀態。
小結:
????鎖的優點:確保了某段關鍵代碼只能由一個線程從頭到尾完整地執行
????鎖的缺點:
? ? ? ? 1- 阻止了多線程并發執行,包含鎖的某段代碼實際上只能以單線程模式執行,效率降低。????????
? ? ????2-由于可以存在多個鎖不同的線程持有不同的鎖,并試圖獲取對方持有鎖時,可能會造成死鎖
五:同步和異步
????同步:
????????????協同步調,按預定的先后次序進行運行。如:買票排隊。
????????????多任務,多個任務之間執行的時候要求有先后順序,必須一個先執行完成之后,另一個才能繼續執行,?只有一個主線。簡言之,同步意味著有序
????異步:
????????????一方的動作不用等另一方動作結果。如:不同窗口買票。
????????????多任務,?多個任務之間執行沒有先后順序,可以同時運行,執行的先后順序不會有什么影響,存在的多條運行主線。簡言之,異步意味著無序。
六:隊列
?1.隊列:先進先出? ? ? ?棧:先進后出
? ? Python的Queue模塊中提供了同步的、線程安全的隊列類,包括FIFO(先進先出)隊列Queue,LIFO(先進后出)隊列LifoQueue,和優先級隊列PriorityQueue。這些隊列都實現了鎖原語(原子性,即要么全做,要么全不做),能夠在多線程中直接使用。可以使用隊列來實現線程間的同步。
? ? 相當于有順序的容器,那為啥要有隊列?
? ? 列表和隊列的根本區別是:取出數據后數據還在不在容器里。
? ??class?queue.Queue(maxsize=0)? ? ? ? ? ? ? ? ? #先進先出
? ??class?queue.LifoQueue(maxsize=0) ????????????#last in fisrt out? 先進后出
? ??class?queue.PriorityQueue(maxsize=0)? ?????#存儲數據時可設置優先級的隊列
?2.Queue的簡要說明
? ? ? ? put():添加數據到隊列中
? ?????????????queue.Queue.put(item,?block=True,?timeout=None)
? ? ? ? get():從隊列中取數據
? ? ? ? ? ? ? ? queue.Queue.get(block=True,timeout=None)
????????qsize():判斷隊列中是否有數據
????????empty():判斷隊列是否為空。如果為空返回True
? ? ? ? full():如果滿了返回True
? ? ? ? put_nowait(item)? 相當于 toput(item,False)
? ? ? ? get_nowait()? ? ? ? ??相當于 toget(False).
? ??????task_done()? ? ? ? ? 任務執行完畢
3.隊列的主要作用
? ? ? ? a.程序解耦
? ? ? ? b.提高效率
七:生產者消費者模型
? ? ? ? 為啥要使用生產者和消費者模式?
????????在線程世界里,生產者就是生產數據的線程,消費者就是消費數據的線程。在多線程開發當中,如果生產者處理速度很快,而消費者處理速度很慢,那么生產者就必須等待消費者處理完,才能繼續生產數據。同樣的道理,如果消費者的處理能力大于生產者,那么消費者就必須等待生產者。為了解決這個問題于是引入了生產者和消費者模式。
????????什么是生產者消費者模式?
????????生產者消費者模式是通過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通訊,而通過阻塞隊列來進行通訊,所以生產者生產完數據之后不用等待消費者處理,直接扔給阻塞隊列,消費者不找生產者要數據,而是直接從阻塞隊列里取,阻塞隊列就相當于一個緩沖區,平衡了生產者和消費者的處理能力。
八:協程
? ??????協程:又稱微線程,纖程。簡單來講:是一種用戶態的輕量級線程。
? ? ? ? ?協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧。基于這點:協程能保留上一次調用時的狀態(即所有局部狀態的一個特定組合),每次過程重入時,就相當于進入上一次調用的狀態,換種說法:進入上一次離開時所處邏輯流的位置。
? ??????優勢:
????????????????無需線程上下文切換的開銷
????????????????無需原子操作鎖定及同步的開銷
????????????????方便切換控制流,簡化編程模型
????????????????高并發+高擴展性+低成本:一個CPU能支持上萬的協程。
?? ??????缺點:
????????????????無法利用多核資源:
? ? ? ? ? ? ? ? 協程本質是個單線程,不能同時將單個CPU的多個核用上,需要和進程配合才能運行在多CPU上.除非cpu密集型應用日常所編寫的絕大部分應用都沒有這個必要。? ? ? ??
????????????????進行阻塞(Blocking)操作(如IO時)會阻塞掉整個程序
? ? ? ? ??協程必備條件:
? ? ? ? ? ? ? ? a.必須在只有一個單線程里實現并發
? ? ? ? ? ? ? ? b.修改共享數據不需要加鎖
? ? ? ? ? ? ? ? c.用戶程序里自己保存多個控制流的上下文棧
? ? ? ? ? ? ? ? d.一個協程遇到IO操作自動切換到其它協程
? ??????????Greenlet:
? ?????????????????greenlet是一個用C實現的協程模塊,可以使你在任意函數間隨意切換。
?? ????????????????問題:上面的Greenlet遇到IO操作不能自動切換。
?? ??????????Gevent:
? ?????????????Gevent 是一個第三方庫,可以輕松通過gevent實現并發同步或異步編程。在gevent中用到的主要模式是Greenlet, 是以C擴展模塊形式接入Python的輕量級協程。 Greenlet全部運行在主程序操作系統進程的內部,但它們被協作式地調度。