咱們都知道計算機是由硬件和軟件組成的。硬件中的CPU是計算機的核心,它承擔計算機的全部任務。 操做系統是運行在硬件之上的軟件,是計算機的管理者,它負責資源的管理和分配、任務的調度。 程序是運行在系統上的具備某種功能的軟件,好比說瀏覽器,音樂播放器等。 每次執行程序的時候,都會完成必定的功能,好比說瀏覽器幫咱們打開網頁,爲了保證其獨立性,就須要一個專門的管理和控制執行程序的數據結構——進程控制塊。 進程就是一個程序在一個數據集上的一次動態執行過程。 進程通常由程序、數據集、進程控制塊三部分組成。咱們編寫的程序用來描述進程要完成哪些功能以及如何完成;數據集則是程序在執行過程當中所須要使用的資源;進程控制塊用來記錄進程的外部特徵,描述進程的執行變化過程,系統能夠利用它來控制和管理進程,它是系統感知進程存在的惟一標誌。
在早期的操做系統裏,計算機只有一個核心,進程執行程序的最小單位,任務調度採用時間片輪轉的搶佔式方式進行進程調度。每一個進程都有各自的一塊獨立的內存,保證進程彼此間的內存地址空間的隔離。 隨着計算機技術的發展,進程出現了不少弊端,一是進程的建立、撤銷和切換的開銷比較大,二是因爲對稱多處理機(對稱多處理機(SymmetricalMulti-Processing)又叫SMP,是指在一個計算機上聚集了一組處理器(多CPU),各CPU之間共享內存子系統以及總線結構)的出現,能夠知足多個運行單位,而多進程並行開銷過大。 這個時候就引入了線程的概念。 線程也叫輕量級進程,它是一個基本的CPU執行單元,也是程序執行過程當中的最小單元,由線程ID、程序計數器、寄存器集合 和堆棧共同組成。線程的引入減少了程序併發執行時的開銷,提升了操做系統的併發性能。 線程沒有本身的系統資源,只擁有在運行時必不可少的資源。但線程能夠與同屬與同一進程的其餘線程共享進程所擁有的其餘資源。
進程與線程之間的關係
線程是屬於進程的,線程運行在進程空間內,同一進程所產生的線程共享同一內存空間,當進程退出時該進程所產生的線程都會被強制退出並清除。線程可與屬於同一進程的其它線程共享進程所擁有的所有資源,可是其自己基本上不擁有系統資源,只擁有一點在運行中必不可少的信息(如程序計數器、一組寄存器和棧)。
python 線程
Threading用於提供線程相關的操做,線程是應用程序中工做的最小單元。
一、threading模塊
threading 模塊創建在 _thread 模塊之上。thread 模塊以低級、原始的方式來處理和控制線程,而 threading 模塊經過對 thread 進行二次封裝,提供了更方便的 api 來處理線程。
上述代碼建立了20個「前臺」線程,而後控制器就交給了CPU,CPU根據指定算法進行調度,分片執行指令。
Thread方法說明
t.start() : 激活線程,
t.getName() : 獲取線程的名稱
t.setName() : 設置線程的名稱
t.name : 獲取或設置線程的名稱
t.is_alive() : 判斷線程是否爲激活狀態
t.isAlive() :判斷線程是否爲激活狀態
t.setDaemon() 設置爲後臺線程或前臺線程(默認:False);經過一個布爾值設置線程是否爲守護線程,必須在執行start()方法以後纔可使用。若是是後臺線程,主線程執行過程當中,後臺線程也在進行,主線程執行完畢後,後臺線程不論成功與否,均中止;若是是前臺線程,主線程執行過程當中,前臺線程也在進行,主線程執行完畢後,等待前臺線程也執行完成後,程序中止
t.isDaemon() : 判斷是否爲守護線程
t.ident :獲取線程的標識符。線程標識符是一個非零整數,只有在調用了start()方法以後該屬性纔有效,不然它只返回None。
t.join() :逐個執行每一個線程,執行完畢後繼續往下執行,該方法使得多線程變得無心義
t.run() :線程被cpu調度後自動執行線程對象的run方法
二、線程鎖threading.RLock和threading.Lock
因爲線程之間是進行隨機調度,而且每一個線程可能只執行n條執行以後,CPU接着執行其餘線程。爲了保證數據的準確性,引入了鎖的概念。因此,可能出現以下問題:
例:假設列表A的全部元素就爲0,當一個線程從前向後打印列表的全部元素,另一個線程則從後向前修改列表的元素爲1,那麼輸出的時候,列表的元素就會一部分爲0,一部分爲1,這就致使了數據的不一致。鎖的出現解決了這個問題。
import threading
import time
globals_num = 0
lock = threading.RLock()
def Func():
for i in range(10):
三、threading.RLock和threading.Lock 的區別
RLock容許在同一線程中被屢次acquire。而Lock卻不容許這種狀況。 若是使用RLock,那麼acquire和release必須成對出現,即調用了n次acquire,必須調用n次的release才能真正釋放所佔用的瑣。
import threading
lock = threading.Lock() #Lock對象
lock.acquire()
lock.acquire() #產生了死瑣。
lock.release()
lock.release()
import threading
rLock = threading.RLock() #RLock對象
rLock.acquire()
rLock.acquire() #在同一線程內,程序不會堵塞。
rLock.release()
rLock.release()
四、threading.Event
python線程的事件用於主線程控制其餘線程的執行,事件主要提供了三個方法 set、wait、clear。
事件處理的機制:全局定義了一個「Flag」,若是「Flag」值爲 False,那麼當程序執行 event.wait 方法時就會阻塞,若是「Flag」值爲True,那麼event.wait 方法時便再也不阻塞。
import threading
def do(event):
event_obj = threading.Event()
for i in range(10):
event_obj.clear()
inp = input('input:')
if inp == 'true':
當線程執行的時候,若是flag爲False,則線程會阻塞,當flag爲True的時候,線程不會阻塞。它提供了本地和遠程的併發性。
五、threading.Condition
一個condition變量老是與某些類型的鎖相聯繫,這個可使用默認的狀況或建立一個,當幾個condition變量必須共享和同一個鎖的時候,是頗有用的。鎖是conditon對象的一部分:沒有必要分別跟蹤。
condition變量服從上下文管理協議:with語句塊封閉以前能夠獲取與鎖的聯繫。 acquire() 和 release() 會調用與鎖相關聯的相應的方法。
其餘和鎖關聯的方法必須被調用,wait()方法會釋放鎖,當另一個線程使用 notify() or notify_all()喚醒它以前會一直阻塞。一旦被喚醒,wait()會從新得到鎖並返回,
Condition類實現了一個conditon變量。 這個conditiaon變量容許一個或多個線程等待,直到他們被另外一個線程通知。 若是lock參數,被給定一個非空的值,,那麼他必須是一個lock或者Rlock對象,它用來作底層鎖。不然,會建立一個新的Rlock對象,用來作底層鎖.
•wait(timeout=None) : 等待通知,或者等到設定的超時時間。當調用這wait()方法時,若是調用它的線程沒有獲得鎖,那麼會拋出一個RuntimeError 異常。 wati()釋放鎖之後,在被調用相同條件的另外一個進程用notify() or notify_all() 叫醒以前 會一直阻塞。wait() 還能夠指定一個超時時間。
若是有等待的線程,notify()方法會喚醒一個在等待conditon變量的線程。notify_all() 則會喚醒全部在等待conditon變量的線程。
注意: notify()和notify_all()不會釋放鎖,也就是說,線程被喚醒後不會馬上返回他們的wait() 調用。除非線程調用notify()和notify_all()以後放棄了鎖的全部權。
在典型的設計風格里,利用condition變量用鎖去通許訪問一些共享狀態,線程在獲取到它想獲得的狀態前,會反覆調用wait()。修改狀態的線程在他們狀態改變時調用 notify() or notify_all(),用這種方式,線程會盡量的獲取到想要的一個等待者狀態。 例子: 生產者-消費者模型,
import threading
import time
def consumer(cond):
def producer(cond):
condition = threading.Condition()
c1 = threading.Thread(name="c1", target=consumer, args=(condition,))
c2 = threading.Thread(name="c2", target=consumer, args=(condition,))
p = threading.Thread(name="p", target=producer, args=(condition,))
c1.start()
time.sleep(2)
c2.start()
time.sleep(2)
p.start()
六、queue模塊
Queue 就是對隊列,它是線程安全的
舉例來講,咱們去麥當勞吃飯。飯店裏面有廚師職位,前臺負責把廚房作好的飯賣給顧客,顧客則去前臺領取作好的飯。這裏的前臺就至關於咱們的隊列。造成管道樣,廚師作好飯經過前臺傳送給顧客,所謂單向隊列
這個模型也叫生產者-消費者模型。
import queue
q = queue.Queue(maxsize=0)
q.join()
q.qsize()
q.empty()
q.full()
q.put(item, block=True, timeout=None) #
爲False時爲非阻塞,此時若是隊列已滿,會引起queue.Full 異常。 可選參數timeout,表示 會阻塞設置的時間,事後,
q.get(block=True, timeout=None) #
若此時隊列爲空,則引起 queue.Empty異常。 可選參數timeout,表示會阻塞設
置的時候,事後,若是隊列爲空,則引起Empty異常。
q.put_nowait(item) #
q.get_nowait() #
代碼以下:
#!/usr/bin/env python
import Queue
import threading
message = Queue.Queue(10)
def producer(i):
def consumer(i):
for i in range(12):
for i in range(10):
那就本身作個線程池吧:
方法一
# 簡單往隊列中傳輸線程數
import threading
import time
import queue
class Threadingpool():
def func(p,i):
if __name__ == "__main__":
方法二
#往隊列中無限添加任務
import queue
import threading
import contextlib
import time
StopEvent = object()
class ThreadPool(object):