執行緒 、程式、協程的基本使用

唯愛程式設計發表於2021-01-21

程式(Process)、執行緒(Thread)、協程(Coroutine)的概念:

程式:
就是正在執行的程式,它是作業系統中,資源分配的最小單位.,
資源分配:分配的是cpu和記憶體等物理資源。
程式號是程式的唯一標識。
預設情況下一個程式只有一個執行緒,在程式裡面可以建立多個執行緒。
執行緒:
cpu執行程式的最小單位, 通過執行緒去執行程式中程式碼, 執行緒是執行程式碼的分支,
執行緒是依附在程式裡面的, 沒有程式就沒有執行緒,
同一個程式執行兩次之後是兩個程式
程式和程式之間的關係: 資料彼此隔離,通過socket通訊
協程:
協程是一種使用者態的輕量級執行緒,協程的排程完全由使用者控制。協程擁有自己的暫存器上下文和棧。協程排程切換時,將暫存器上下文和棧儲存到其他地方,在切回來的時候,恢復先前儲存的暫存器上下文和棧,直接操作棧則基本沒有核心切換的開銷,可以不加鎖的訪問全域性變數,所以上下文的切換非常快。
協程在子程式內部可中斷的,然後轉而執行別的子程式,在適當的時候再返回來接著執行。

並行和併發

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

同步和非同步

  • 同步是指代在程式執行多個任務時,按部就班的依次執行,必須上一個任務執行完有了結果以後,才會執行下一個任務。
  • 非同步是指代在程式執行多個任務時,沒有先後依序,可以同時執行,所以在執行上一個任務時不會等待結果,直接執行下一個任務。一般最終在下一個任務中通過狀態的改變或者通知、回撥的方式來獲取上一個任務的執行結果。

cpu的程式排程方法

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

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

程式的性質:

  1. 程式之間的資料彼此隔離
  2. 多個程式之間是非同步併發

–程式(Process):

程式的基本使用:

import os, time, random
from multiprocessing import Process
def func(n):
    time.sleep(random.randrange(3))
    print("數字{}<=>1.子程式id>>{},2父程式id>>{}".format(n, os.getpid(), os.getppid()))
	
if __name__ == "__main__":
    for i in range(1, 11):
        # 建立子程式,返回程式物件,執行func這個任務
        p = Process(target=func, args=(i,))  # args=(i,)傳遞引數
        # 呼叫子程式
        p.start()  # 可簡寫成 Process(target=func, args=(i,)).start()
    print("主程式執行結束了....")
    print(os.getpid())  # os.getpid()程式號

執行檢視:
在這裡插入圖片描述
執行檢視不唯一,因為多個程式之間是非同步併發

程式的join 函式:

  1. join 等待當前子程式全部執行完畢之後,主程式在執行(用來同步子父程式的)

例:

p = Process(target=func,args=(i,))
p.join()

同步 非同步 / 阻塞 非阻塞

  • 同步:必須等我這件事幹完了,你在幹,只有一條主線,就是同步
  • 非同步:沒等我這件事情幹完,你就在幹了,有兩條主線,就是非同步
  • 阻塞:比如程式碼有了input,就是阻塞,必須要輸入一個字串,否則程式碼不往下執行
  • 非阻塞:沒有任何等待,正常程式碼往下執行.
  • 同步阻塞 :效率低,cpu利用不充分
  • 非同步阻塞 :比如socketserver,可以同時連線多個,但是彼此都有recv
  • 同步非阻塞:沒有類似input的程式碼,從上到下執行.預設的正常情況程式碼

事件 (Event)

  • 非同步非阻塞:效率是最高的,cpu過度充分,過度發熱 液冷

事件 (Event)阻塞事件 :

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

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

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

Event_test.py:

在這裡插入程式碼片

控制這個屬性的值

# set()方法     將這個屬性的值改成True
# clear()方法   將這個屬性的值改成False
# is_set()方法  判斷當前的屬性是否為True  (預設上來是False)
在這裡插入程式碼片
場景在多工當中
同步:必須等我這件事幹完了,你在幹,只有一條主線,就是同步
非同步:沒等我這件事情幹完,你就在幹了,有兩條主線,就是非同步
阻塞:比如程式碼有了input,就是阻塞,必須要輸入一個字串,否則程式碼不往下執行
非阻塞:沒有任何等待,正常程式碼往下執行.
 
# 同步阻塞  :效率低,cpu利用不充分
# 非同步阻塞  :比如socketserver,可以同時連線多個,但是彼此都有recv
# 同步非阻塞:沒有類似input的程式碼,從上到下執行.預設的正常情況程式碼
# 非同步非阻塞:效率是最高的,cpu過度充分,過度發熱 液冷

守護程式

守護程式守護的是主程式,如果主程式中的所有程式碼執行完畢了,
當前這個守護程式會被立刻殺死,立刻終止.
語法:
程式.daemon = True 設定當前這個程式為守護程式
必須寫在start()呼叫程式之前進行設定

預設:主程式會預設等待所有子程式執行結束之後,在關閉程式,釋放資源
程式碼:

from multiprocessing import Process
import time
# (3) 守護程式實際用途: 監控報活
# 守護進行
def alive():
	while True:
		print("給監控的總伺服器發訊息,報告自己的存活狀態, i am alive~")
		time.sleep(1)

# 執行任務
def func():
	while True:
		try:
			time.sleep(1)
			raise RuntimeError
			print("當前5號伺服器功能:對日誌進行資料分析.... ")
		except:
			break
			# pass

if __name__ == "__main__":
	# 建立2個子程式
	p1 = Process(target=alive)
	p2 = Process(target=func)
	# 設定p1為守護程式
	# p1.daemon = True
	p1.start()
	p2.start()
	# 必須等到p2任務執行結束之後,在向下執行.
	p2.join()
	print("當前伺服器狀態異常 ... ")


沒有設定守護程式檢視:
在這裡插入圖片描述
設定守護程式檢視:
在這裡插入圖片描述

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

鎖(Lock)

上鎖和解鎖是一對,只上鎖不解鎖會發生死鎖現象(程式碼阻塞,不往下執行了)
互斥鎖 : 互斥鎖是程式之間的互相排斥,誰先搶到這個鎖資源就先使用,後搶到後使用
訊號量:Semaphore 本質上就是鎖,只不過可以控制上鎖的數量
look:
lock.acquire()# 上鎖
lock.release()# 解鎖

# 建立一把鎖
lock = Lock() 
# 上鎖
lock.acquire()
# 連續上鎖不解鎖是死鎖
# lock.acquire() error

print("廁所中...")

# 解鎖
lock.release()
print("執行程式 ... ")

Semaphore:

from multiprocessing import Semaphore,Process
import time,random
sem = Semaphore(4)
sem.acquire()
# sem.acquire()
# sem.acquire()
# sem.acquire()
# sem.acquire() # 上第五把鎖出現死鎖狀態.
print("執行響應的操作") 
sem.release()
"""
# 總結:
Semaphore 可以設定上鎖的數量
同一時間最多允許幾個程式上鎖
建立程式的時候,是非同步併發
執行任務的時候,遇到鎖會變成同步程式.
"""
lock.acquire()# 上鎖
lock.release()# 解鎖
#同一時間允許一個程式上一把鎖 就是Lock
	加鎖可以保證多個程式修改同一塊資料時,同一時間只能有一個任務可以進行修改,即序列的修改,沒錯,速度是慢了,但犧牲速度卻保證了資料安全。
#同一時間允許多個程式上多把鎖 就是[訊號量Semaphore]
	訊號量是鎖的變形: 實際實現是 計數器 + 鎖,同時允許多個程式上鎖	

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

事件(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() 	   檢測是否已經存滿 (瞭解)

–執行緒(Thread)

生產者與消費者模型

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-LYUQwS07-1611230808561)(assets/生產者消費者.png)]

相關文章