1. 程式人生 > 其它 >程序 執行緒 協程

程序 執行緒 協程

程序的概念:(Process)

程序就是正在執行的程式,它是作業系統中,資源分配的最小單位.
資源分配:分配的是cpu和記憶體等物理資源
程序號是程序的唯一標識

同一個程式執行兩次之後是兩個程序
程序和程序之間的關係: 資料彼此隔離,通過socket通訊

並行和併發

併發:一個cpu同一時間不停執行多個程式
並行:多個cpu同一時間不停執行多個程式

cpu的程序排程方法

# 先來先服務fcfs(first come first server):先來的先執行
# 短作業優先演算法:分配的cpu多,先把短的算完
# 時間片輪轉演算法:每一個任務就執行一個時間片的時間.然後就執行其他的.
# 多級反饋佇列演算法

越是時間長的,cpu分配的資源越短,優先順序靠後
越是時間短的,cpu分配的資源越多

程序三狀態圖

(1)就緒(Ready)狀態
只剩下CPU需要執行外,其他所有資源都已分配完畢 稱為就緒狀態。
(2)執行(Running)狀態
cpu開始執行該程序時稱為執行狀態。
(3)阻塞(Blocked)狀態
由於等待某個事件發生而無法執行時,便是阻塞狀態,cpu執行其他程序.例如,等待I/O完成input、申請緩衝區不能滿足等等。

同步 非同步 / 阻塞 非阻塞

場景在多工當中
同步:必須等我這件事幹完了,你在幹,只有一條主線,就是同步
非同步:沒等我這件事情幹完,你就在幹了,有兩條主線,就是非同步
阻塞:比如程式碼有了input,就是阻塞,必須要輸入一個字串,否則程式碼不往下執行
非阻塞:沒有任何等待,正常程式碼往下執行.

# 同步阻塞 :效率低,cpu利用不充分
# 非同步阻塞 :比如socketserver,可以同時連線多個,但是彼此都有recv
# 同步非阻塞:沒有類似input的程式碼,從上到下執行.預設的正常情況程式碼
# 非同步非阻塞:效率是最高的,cpu過度充分,過度發熱

守護程序

#可以給子程序貼上守護程序的名字,該程序會隨著主程序程式碼執行完畢而結束(為主程序守護)
(1)守護程序會在主程序程式碼執行結束後就終止
(2)守護程序內無法再開啟子程序,否則丟擲異常(瞭解)

鎖(Lock)

lock.acquire()# 上鎖
lock.release()# 解鎖

#同一時間允許一個程序上一把鎖 就是Lock
加鎖可以保證多個程序修改同一塊資料時,同一時間只能有一個任務可以進行修改,即序列的修改,沒錯,速度是慢了,但犧牲速度卻保證了資料安全。
#同一時間允許多個程序上多把鎖 就是[訊號量Semaphore]
訊號量是鎖的變形: 實際實現是 計數器 + 鎖,同時允許多個程序上鎖

# 互斥鎖Lock : 互斥鎖就是程序的互相排斥,誰先搶到資源,誰就上鎖改資源內容,為了保證資料的同步性
# 注意:多個鎖一起上,不開鎖,會造成死鎖.上鎖和解鎖是一對.

訊號量

# ### 訊號量 Semaphore (執行緒)

"""同一時間對多個執行緒上多把鎖"""
from threading import Thread,Semaphore
import time , random

def func(i,sem):
    time.sleep(random.uniform(0.1,0.7))
    # with語法自動實現上鎖 + 解鎖
    with sem:        
        print("我在電影院拉屎 .... 我是{}號".format(i))
        

if __name__ == "__main__":
    sem = Semaphore(5)
    for i in range(30):
        Thread(target=func,args=(i,sem)).start()
    print(1)
"""
    建立執行緒是非同步的,
    上鎖的過程會導致程式變成同步;
"""        

事件(Event)

# 阻塞事件 :
e = Event()生成事件物件e
e.wait()動態給程式加阻塞 , 程式當中是否加阻塞完全取決於該物件中的is_set() [預設返回值是False]
# 如果是True 不加阻塞
# 如果是False 加阻塞

# 控制這個屬性的值
# set()方法 將這個屬性的值改成True
# clear()方法 將這個屬性的值改成False
# is_set()方法 判斷當前的屬性是否為True (預設上來是False)

程序間通訊 IPC

# IPC Inter-Process Communication
# 實現程序之間通訊的兩種機制:
# 管道 Pipe
# 佇列 Queue

# put() 存放
# get() 獲取
# get_nowait() 拿不到報異常
# put_nowait() 非阻塞版本的put
q.empty() 檢測是否為空 (瞭解)
q.full() 檢測是否已經存滿 (瞭解)

生產者與消費者模型

# ### 生產者和消費者模型 
"""
# 爬蟲案例
1號程序負責抓取其他多個網站中相關的關鍵字資訊,正則匹配到佇列中儲存(mysql)
2號程序負責把佇列中的內容拿取出來,將經過修飾後的內容佈局到自個的網站中

1號程序可以理解成生產者
2號程序可以理解成消費者

從程式上來看 
    生產者負責儲存資料 (put)
    消費者負責獲取資料 (get)
    
生產者和消費者比較理想的模型:
    生產多少,消費多少 . 生產資料的速度 和 消費資料的速度 相對一致    
"""

程序池

# 程序池:
# 開啟過多的程序並不一定提高你的效率,
# 如果cpu負載任務過多,平均單個任務執行的效率就會低,反而降低執行速度.
1個人做4件事,4個人做4件事,4個人做1件事
顯然後者執行速度更快,
前者是併發,後者是並行
利用程序池,可以開啟cpu的並行效果
# apply 開啟程序,同步阻塞,每次都要等待當前任務完成之後,在開啟下一個程序
# apply_async 開啟程序,非同步非阻塞,(主程序 和 子程序非同步)

執行緒

#程序是資源分配的最小單位
#執行緒是計算機中排程的最小單位

#執行緒的緣起
資源分配需要分配記憶體空間,分配cpu:
分配的記憶體空間存放著臨時要處理的資料等,比如要執行的程式碼,資料
而這些記憶體空間是有限的,不能無限分配
目前配置高的主機,5萬個併發已是上限.執行緒概念應用而生.

#執行緒的特點
執行緒是比較輕量級,能幹更多的活,一個程序中的所有執行緒資源是共享的.
一個程序至少有一個執行緒在工作

執行緒的缺陷

#python中的執行緒可以併發,但是不能並行(同一個程序下的多個執行緒不能分開被多個cpu同時執行)
#原因:
全域性直譯器鎖(Cpython直譯器特有) GIL鎖:
同一時間,一個程序下的多個執行緒只能被一個cpu執行,不能實現執行緒的並行操作
python是解釋型語言,執行一句編譯一句,而不是一次性全部編譯成功,不能提前規劃,都是臨時排程
容易造成cpu執行排程異常.所以加了一把鎖叫GIL

#想要並行的解決辦法:
(1)用多程序間接實現執行緒的並行
(2)換一個Pypy,Jpython直譯器

#程式分為計算密集型和io密集型
對於計算密集型程式會過度依賴cpu,但網頁,爬蟲,OA辦公,這種io密集型的程式裡,python綽綽有餘

執行緒相關函式

執行緒.is_alive()   檢測執行緒是否仍然存在
執行緒.setName() 設定執行緒名字
執行緒.getName() 獲取執行緒名字
1.currentThread().ident 檢視執行緒id號
2.enumerate() 返回目前正在執行的執行緒列表
3.activeCount() 返回目前正在執行的執行緒數量

死鎖,遞迴鎖,互斥鎖

加一把鎖,就對應解一把鎖.形成互斥鎖.
從語法上來說,鎖可以互相巢狀,但不要使用,
不要因為邏輯問題讓上鎖分成兩次.導致死鎖
遞迴鎖用於解決死鎖,但只是一種應急的處理辦法

執行緒佇列

執行緒常用佇列有 queue LifoQueue PriorityQueue
queue 先進先出
LifoQueue 後進先出
PriorityQueue 按照優先順序排序

執行緒池和程序池 (改良版)

# 執行緒池
# 例項化執行緒池 ThreadPoolExcutor (推薦5*cpu_count)
# 非同步提交任務 submit / map
# 阻塞直到任務完成 shutdown
# 獲取子執行緒的返回值 result
# 使用回撥函式 add_done_callback

# 回撥函式
就是一個引數,將這個函式作為引數傳到另一個函式裡面.
函式先執行,再執行當引數傳遞的這個函式,這個引數函式是回撥函式

# 執行緒池 是由子執行緒實現的
# 程序池 是由主程序實現的

協程(gevent)

3.#協程也叫纖程: 協程是執行緒的一種實現方式.
指的是一條執行緒能夠在多工之間來回切換的一種實現.
對於CPU、作業系統來說,協程並不存在.
任務之間的切換會花費時間.
目前電腦配置一般執行緒開到200會阻塞卡頓.

#協程的實現
協程幫助你記住哪個任務執行到哪個位置上了,並且實現安全的切換
一個任務一旦阻塞卡頓,立刻切換到另一個任務繼續執行,保證執行緒總是忙碌的,更加充分的利用CPU,搶佔更多的時間片
# 一個執行緒可以由多個協程來實現,協程之間不會產生資料安全問題

#協程模組
# greenlet gevent的底層,協程,切換的模組
# gevent 直接用的,gevent能提供更全面的功能

GIL鎖​