Python全棧之進程和守護進程

1. 理解進程

進程的概念:(process

進程就是正在運行的程序,它是操作系統中,資源分配的最小單位.
資源分配:分配的是cpu和內存等物理資源
進程號是進程的唯一標識
同一個程序執行兩次之後是兩個進程
進程和進程之間的關系: 數據彼此隔離,通過socket通信

並行和並發

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

cpu的進程調度的方法:

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

1、2、3、4作業分別給0.4秒,1作業完成,2、3、4作業沒有完成,會放到二級隊列中,把後續短的作業放到一級隊列。二級隊列中的作業分別給0.3秒,2號作業完成,3、4號作業放到三級隊列,分別給0.2秒,3作業完成,4號沒有完成,放到四號隊列,給0.1秒進行處理,1號作業有可能是下載作業。

進程三狀態圖:

(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 : 互斥鎖就是進程的互相排斥,誰先搶到資源,誰就上鎖改資源內容,為瞭保證數據的同步性
# 註意:多個鎖一起上,不開鎖,會造成死鎖.上鎖和解鎖是一對.

2. 進程的語法

# ### 進程 process
import os,time
"""
# ps -aux 查看進程號
# ps -aux | grep 2784 過濾查找2784這個進程
# 強制殺死進程
kill -9 進程號
# 獲取當前進程號
res = os.getpid()
print(res)
# 獲取當前進程的父進程
res = os.getppid()
print(res)
"""
from multiprocessing import Process
# (1) 進程的使用
"""
def func():
	# 1.子進程id:3561,2.父進程id:3560
	print("1.子進程id:{},2.父進程id:{}".format(os.getpid(),os.getppid()))
if __name__ == "__main__":
	# 創建子進程 ,返回進程對象
	p = Process(target=func)
	# 調用子進程
	p.start()
	# 3.主進程id:3560,4.父進程id:3327
	print("3.主進程id:{},4.父進程id:{}".format(os.getpid(),os.getppid()))
"""
# (2) 創建帶有參數的進程
"""
def func(n):
	time.sleep(1)
	for i in range(1,n+1): # 0 ~ n-1
		print(i)
		print("1.子進程id:{},2.父進程id:{}".format(os.getpid(),os.getppid()))
if __name__ == "__main__":
	n = 6
	# target=指定任務  args = 參數元組
	p = Process(target=func , args=(n,))
	p.start()
	for i in range(1,n+1):
		print("*" * i)
"""
# (3) 進程之間的數據彼此隔離
"""
total = 100
def func():
	global total
	total +=1
	print(total)
if __name__ == "__main__":
	p = Process(target=func)
	p.start()
	time.sleep(1)
	print(total)
"""
# (4) 進程之間的異步性
"""
1.多個進程之間是異步的並發程序,因為cpu調度策略問題,不一定先執行哪一個任務
默認來看,主進程執行速度稍快於子進程,因為子進程創建時,要分配空間資源可能會阻塞
阻塞態,cpu會立刻切換任務,以讓程序整體的速度效率最大化
2.默認主進程要等待所有的子進程執行結束之後,在統一關閉程序,釋放資源
若不等待,子進程可能不停的在系統的後臺占用cpu和內存資源形成僵屍進程.
為瞭方便進程的管理,主進程默認等待子進程.在統一關閉程序;
"""
def func(n):
	print("1.子進程id:{},2.父進程id:{}".format(os.getpid(),os.getppid()) , n )
if __name__ == "__main__":
	for i in range(1,11):
		p = Process(target=func,args=(i,))
		p.start()
	print("主進程執行結束瞭 ... " , os.getpid() )

3. join自定義進程類

子進程全部執行完,在執行主進程

# ### 1.同步主進程和子進程 : join
"""必須等待當前的這個子進程執行結束之後,再去執行下面的代碼;,用來同步子父進程;"""
from multiprocessing import Process
import time 
# (1) join 的基本使用
"""
def func():
	print("發送第一封郵件 :  我的親親領導,你在麼?")	
if __name__ == "__main__":
	p = Process(target=func)
	p.start()
	# time.sleep(0.1)
	p.join()
	print("發送第二封郵件 :  我想說,工資一個月給我漲到6萬")
"""
# (2) 多進程場景中的join
"""
def func(i):
	time.sleep(1)
	print("發送第一封郵件{} :  我的親親領導,你在麼?".format(i))
if __name__ == "__main__":
	lst = []
	for i in range(1,11):
		p = Process(target=func,args=(i,))
		p.start()
		# join 寫在裡面會導致程序變成同步
		lst.append(p)
	# 把所有的進程對象都放在列表中,統一使用.join進行管理;
	for i in lst:
		i.join()
		
	print("發送第二封郵件 :  我想說,工資一個月給我漲到6萬")
"""
# ### 2使用自定義進程類,創建進程
# (1) 基本語法
import os
class MyProcess(Process):
	def run(self):
		print("1.子進程id:{},2.父進程id:{}".format(os.getpid(),os.getppid()))
if __name__ == "__main__":
	p = MyProcess()
	p.start()
	
# (2) 帶有參數的自定義進程類
class MyProcess(Process):
	def __init__(self,name):
		# 手動調用一下父類的構造方法,完成系統成員的初始化;
		super().__init__()
		self.name = name
	def run(self):
		print("1.子進程id:{},2.父進程id:{}".format(os.getpid(),os.getppid()))
		print(self.name)
if __name__ == "__main__":
	p = MyProcess("我是參數")
	p.start()

4. 守護進程

# ### 守護進程
"""
守護進程守護的是主進程,當主進程所有代碼執行完畢之後,立刻強制殺死守護進程;
"""

from multiprocessing import Process
import time
# (1) 基本語法
"""
def func():
	# time.sleep(1)
	print("start... 當前的子進程")
	print("end ...  當前的子進程")

if __name__ == "__main__":
	p = Process(target=func)
	# 在進程啟動之前,設置守護進程
	p.daemon = True	
	p.start()	
	print("主進程執行結束 ... ")
"""
# (2) 多個子進程的守護場景;
"""默認主進程等待所有非守護進程,也就是子進程執行結束之後,在關閉程序,釋放資源
守護進程隻要在主進程代碼執行結束時,就會自動關閉;
"""
"""
def func1():
	print("start ... func1 執行當前子進程 ... ")
	print("end ...   func1 結束當前子進程 ... ")
def func2():
	count = 1
	while True:
		print("*" * count)
		time.sleep(1)
		count += 1
if __name__ == "__main__":
	p1 = Process(target=func1)
	p2 = Process(target=func2)
	# 把p2這個進程變成守護進程;
	p2.daemon = True
	p1.start()
	p2.start()
	print("主進程執行結束 ... ")
"""
# (3) 守護進程用途: 監控報活
def alive():
	while True:
		print("3號服務器向總監控服務器發送報活信息: i am ok~")
		time.sleep(1)
def func():
	while True:
		try:
			print("3號服務器負責抗住3萬用戶量的並發訪問...")
			time.sleep(3)
			# 主動拋出執行錯誤的異常,觸發except分支
			raise RuntimeError			
		except:
			print("3號服務器扛不住瞭.. 快來修理我..")
			break
			
if __name__ == "__main__":
	p1 = Process(target=alive)
	p2 = Process(target=func)
	p1.daemon = True
	p1.start()
	p2.start()
	# 必須等待p2這個子進程執行完畢之後,再放行主進程下面的代碼
	# 下面主進程代碼執行結束,立刻殺死守護進程,失去瞭報活功能;
	p2.join()
	
	print("主進程執行結束  .... ")

#作業:
""" 使用多進程的方式  完成tcp服務端的並發 """

小提示:

在調用的時候觸發裝飾器
連續發包的時候才會粘包
容器不能轉化成字節流,機器交互用json
文件對象是迭代器,迭代器返回的數據是一行行返回的
創建子進程的時候,要為其分配資源,處於堵塞狀態,
會去執行下面的程序,這就是異步執行,兩條主線
不刷新頁面就能發文數據的技術叫ajax,是一種異步程序
進程是典型的異步程序
看一下super()這個函數
默認主進程走完瞭守護進程會立即被殺死,但是會等待子進程運行完畢

總結

本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!

推薦閱讀: