基本概念
1.進程
定義: 進程就是一個程序在一個數據集上的一次動態執行過程。安全
組成: 進程通常由程序、數據集、進程控制塊三部分組成。多線程
程序: 咱們編寫的程序用來描述進程要完成哪些功能以及如何完成;併發
數據集: 則是程序在執行過程當中所須要使用的資源;app
進程控制塊: 用來記錄進程的外部特徵,描述進程的執行變化過程,系統能夠利用它來控制和管理進程,它是系統感知進程存在的惟一標誌異步
2.線程
線程的出現是爲了下降上下文切換的消耗,提升系統的併發性,並突破一個進程只能幹同樣事的缺陷,使到進程內併發成爲可能。ide
線程也叫輕量級進程,它是一個基本的CPU執行單元,也是程序執行過程當中的最小單元函數
組成:由線程ID、程序計數器、寄存器集合和堆棧共同組成。post
線程的引入減少了程序併發執行時的開銷,提升了操做系統的併發性能。線程沒有本身的系統資源性能
3.線程與進程的區別
- 線程是執行的指令集 , 進程是資源的集合
- 線程的啓動速度要比進程的啓動速度要快
- 兩個線程的執行速度是同樣的
- 進程與線程的運行速度是沒有可比性的
- 線程共享建立它的進程的內存空間 , 進程的內存是獨立的
- 兩個線程共享的數據都是同一份數據 , 兩個子進程的數據不是共享的 , 並且數據是獨立的
- 同一個進程的線程之間能夠直接交流 , 同一個主進程的多個子進程之間是不能夠進行交流 , 若是兩個進程之間須要通訊 , 就必需要經過一箇中間代理來實現
- 一個新的線程很容易被建立 , 一個新的進程建立須要對父進程進行一次克隆
- 一個線程能夠控制和操做同一個進程裏的其餘線程 , 線程與線程之間沒有隸屬關係 , 可是進程只能操做子進程
- 改變主線程 , 有可能會影響到其餘線程的行爲 , 可是對於父進程的修改是不會影響子進程
4.同步和異步
同步就是指一個進程在執行某個請求的時候,若該請求須要一段時間才能返回信息,那麼這個進程將會一直等待下去,直到收到返回信息才繼續執行下去;ui
異步是指進程不須要一直等下去,而是繼續執行下面的操做,無論其餘進程的狀態。當有消息返回時系統會通知進程進行處理,這樣能夠提升執行的效率。
舉個例子,打電話時就是同步通訊,發短息時就是異步通訊
5.並行和併發
並行指系統具備處理多個任務(動做)的能力
併發是指系統具備同時處理多個任務(動做)的能力
6.阻塞與非阻塞
阻塞調用是指調用結果返回以前,當前線程會被掛起(如遇到io操做)。函數只有在獲得結果以後纔會將阻塞的線程激活。
非阻塞和阻塞的概念相對應,指在不能馬上獲得結果以前也會馬上返回,同時該函數不會阻塞當前線程
線程threading模塊
![](http://static.javashuo.com/static/loading.gif)
import threading import time def run(n): #定義線程要運行的函數 print('task',n) time.sleep(2) if __name__ == '__main__': t1 = threading.Thread(target=run,args=(1,)) #生成一個線程 t2 = threading.Thread(target=run,args=(2,)) t1.start() t2.start() print('I am main thread') #主線程 #這個進程裏面有三個線程,1個主線程,t1,t2兩個子線程 #子線程和主線程是同步開啓的,主線程結束後,要等子線程所有結束後,進程纔會關閉
![](http://static.javashuo.com/static/loading.gif)
import threading,time class MyThread(threading.Thread): #繼承threading,Thread模塊 def __init__(self,n): super(MyThread, self).__init__() #繼承父類 self.n = n def run(self): #必須用run print('task',self.n) time.sleep(2) t1 = MyThread(1) t2 = MyThread(2) t1.start() t2.start() print('I am main thread') print(t1.is_alive()) #返回線程是否活動的。 print(t1.getName()) #返回線程名。 t1.setName('我是T1') #設置線程名。 print(t1.getName()) print(threading.currentThread()) #查看當前線程是主線程(mainThread)仍是子線程(Thread) print(threading.activeCount()) #返回正在運行的線程數量 結果: task 1 task 2 I am main thread True Thread-1 我是T1 <_MainThread(MainThread, started 9580)> 3 Process finished with exit code 0
join和setDaemon
主線程 : 當一個程序啓動時 , 就有一個進程被操做系統建立 , 與此同時一個線程也馬上運行 , 該線程一般叫作程序的主線程
子線程 : 由於程序是開始時就執行的 , 若是你須要再建立線程 , 那麼建立的線程就是這個主線程的子線程
join的做用:是保證當前線程執行完成後,再執行其它線程
![](http://static.javashuo.com/static/loading.gif)
import threading import time def run(n): print("task ",n ) time.sleep(2) start_time = time.time() t_objs = [] #存線程實例 for i in range(50): #生成50個線程 t = threading.Thread(target=run,args=("t-%s" %i ,)) t.start() t_objs.append(t) #爲了避免阻塞後面線程的啓動,不在這裏join,先放到一個列表裏 for t in t_objs: #循環線程實例列表,等待全部線程執行完畢 t.join() print("---all threads has finished...") print("cost:",time.time() - start_time)
setDaemon
將線程聲明爲守護線程,必須在start() 方法調用以前設
setDaemon(),只要主線程完成了,無論子線程是否完成,都要和主線程一塊兒退出
![](http://static.javashuo.com/static/loading.gif)
import threading import time def run(n): print('task',n) time.sleep(2) print('i am 子線程') #主線程結束,setDaemon無論有沒有運行完都會被銷燬 if __name__ == '__main__': t1 = threading.Thread(target=run,args=(1,)) t2 = threading.Thread(target=run,args=(2,)) t1.setDaemon(True) #設置守護線程,放在start以前 t1.start() t2.setDaemon(True) t2.start() print('I am main thread') 結果: task 1 task 2 I am main thread
線程鎖(互斥鎖Mutex)
lock:若是有多個進程對同一文件進行修改 , 就會形成錯亂 , 因此咱們爲了保護文件數據的安全 , 就須要給其進行加鎖,join爲總體串行 , lock爲局部串行
Rlock:在線程間共享多個資源的時候,若是兩個線程分別佔有一部分資源而且同時等待對方的資源,就會形成死鎖,由於系統判斷這部分資源都正在使用,全部這兩個線程在無外力做用下將一直等待下去。
Rlock就是解決死鎖的問題。
![](http://static.javashuo.com/static/loading.gif)
import time import threading def addNum(): global num #在每一個線程中都獲取這個全局變量 print('--get num:',num ) time.sleep(1) lock.acquire() #修改數據前加鎖 num -=1 #對此公共變量進行-1操做 lock.release() #修改後釋放 num = 100 #設定一個共享變量 thread_list = [] lock = threading.Lock() #生成全局鎖 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 )
![](http://static.javashuo.com/static/loading.gif)
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: 1 print(threading.active_count()) else: print('----all threads done---') print(num, num2)
semaphore(信號量)
![](http://static.javashuo.com/static/loading.gif)
import threading, time def run(n): semaphore.acquire() time.sleep(1) print("run the thread: %s\n" % n) semaphore.release() if __name__ == '__main__': semaphore = threading.BoundedSemaphore(5) # 最多容許5個線程同時運行 for i in range(22): t = threading.Thread(target=run, args=(i,)) t.start() while threading.active_count() != 1: pass else: print('----all threads done---')
queue(隊列)
![](http://static.javashuo.com/static/loading.gif)
import queue #queue #主要做用:解耦 # 提升運行效率 q =queue.Queue() #生成一個隊列對象 先入先出 q.put('1') #put item into the queue q.put('2') q.put('3') q.qsize() #看隊列大小 q.get() #從隊列中取 q.get(block=True, timeout=None) #取不到數據,默認阻塞,timeout設置阻塞時間 q.get_nowait() #若是隊列爲空,取不到數據,拋出異常,不會阻塞卡主 q = queue.Queue(maxsize=3) #maxsize能夠設置隊列的大小,最多容許存三個 q = queue.PriorityQueue #優先級 print(q.full()) #判斷隊列是否有數據 返回blue值 print(q.empty()) #判斷隊列是不是空 返回blue值
生產者消費者模型
爲何要使用生產者和消費者模式
在線程世界裏,生產者就是生產數據的線程,消費者就是消費數據的線程。在多線程開發當中,若是生產者處理速度很快,而消費者處理速度很慢,那麼生產者就必須等待消費者處理完,才能繼續生產數據。一樣的道理,若是消費者的處理能力大於生產者,那麼消費者就必須等待生產者。爲了解決這個問題因而引入了生產者和消費者模式。
什麼是生產者消費者模式
生產者消費者模式是經過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通信,而經過阻塞隊列來進行通信,因此生產者生產完數據以後不用等待消費者處理,直接扔給阻塞隊列,消費者不找生產者要數據,而是直接從阻塞隊列裏取,阻塞隊列就至關於一個緩衝區,平衡了生產者和消費者的處理能力。
![](http://static.javashuo.com/static/loading.gif)
import threading,time import queue q = queue.Queue(maxsize=5) #設置maxsize=5,防止生產過快 def Producer(name): #生產者 count = 1 while True: q.put("麪包%s" % count) print("%s生產了麪包%s"%(name,count)) count +=1 time.sleep(0.1) def Consumer(name): #消費者 while True: print("[%s] 取到[%s] 而且吃了它..." %(name, q.get())) time.sleep(1) #生成多個線程 p = threading.Thread(target=Producer,args=("derek",)) c = threading.Thread(target=Consumer,args=("chihuo1",)) c1 = threading.Thread(target=Consumer,args=("chihou2",)) p.start() c.start() c1.start()
Events
event = threading.Event()
# a client thread can wait for the flag to be set
event.wait()
# a server thread can set or reset it
event.set()
event.clear()
If the flag is set, the wait method doesn’t do anything.
If the flag is cleared, wait will block until it becomes set again.
Any number of threads may wait for the same event.
![](http://static.javashuo.com/static/loading.gif)
import time import threading event = threading.Event() def lighter(): #紅綠燈 count = 0 event.set() #set flag 初始綠燈 while True: if count >5 and count < 10: #改爲紅燈 event.clear() #把標誌位清了 print("如今是紅燈") elif count >10: event.set() #變綠燈 count = 0 else: print("如今是綠燈") time.sleep(1) count +=1 def car(name): while True: if event.is_set(): #判斷the flag 是否is set 表明綠燈 print("[%s] running..."% name ) time.sleep(1) else: print("[%s] waiting ...... " %name) event.wait() #等flag被set print("綠燈亮了,%s能夠走了" %name) time.sleep(1) light = threading.Thread(target=lighter,) light.start() car1 = threading.Thread(target=car,args=("Tesla",)) car1.start()