day28 進程(Process)
1、進程的概念
進程(Process)是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。
# 進程是系統進行資源分配和調度的基本單位
程序:做事的過程,而且是沒有生命周期的,程序是永久的
進程:是動態的,是有生命周期的,進程是暫時的
協程:解決單線程下的高並發
# 進程中還可以開線程
線程就是干活的人,進程不是干活的人
線程就是最小的執行單元
進程和線程都是有操作系統來調度的
2、進程的並行和並發
一、進程的並行和並發
並行: 並行是指兩者同時執行,比如賽跑,兩個人都在不停的往前跑(比如三個線程,四核的CPU)
並發:並發是指資源有限的情況下,兩者交替輪流使用資源(比如單核CPU,只能兩個人來回交替使用,目的是提高效率)
二、並行和並發的區別
並行是從微觀上,就是在一個精確的時間片刻,有不同的程序在同時執行,這就要求必須有多個處理器。
並發是從宏觀上,在一個時間段可以看出是同時執行的,# 但原理是多個程序來回交替使用的。
三、消耗
1. i/o消耗(i/o密集型)
input:輸入
output:輸出
不需要用到CPU的
比如:在一個網站下載文件,下載時間為3秒,這個過程及時i/o消耗
2.計算密集型
需要占用CPU
3、進程調度算法
一、先來先服務調度算法
先來先服務調度算法是一種最簡單的調度算法,該算法既可以用於作業調度,也可用於進程調度。FCFS算法比較有利於長作業(進程),而不利於短作業(進程)。由此可知,本算法適合於CPU繁忙型作業,而不利於O/O繁忙型的作業(進程)。
二、短作業優先調度算法
短作業(進程)優先調度算法是指對短作業或短進程優先調度的算法,該算法既可用於作業調度,也可用於進程調度。
三、時間片輪轉法
時間片輪轉法的基本思路是讓每個進程在就緒隊列中的等待時間與享受服務的時間成比列。
4、同步異步阻塞和非阻塞
# 在程序運行的過程中,由於被操作系統的調度算法控制,程序會進入幾個狀態:就緒,運行和阻塞。
1.同步與異步: 同步和異步關注的是消息通信機制
2. 阻塞與非阻塞:阻塞和非阻塞關注的是程序在等待調用結果(消息,返回值)時的狀態.
同步:就是一個任務的完成需要依賴另外一個任務時,只有等待被依賴的任務才算完成,這是一種可靠序列。要么成功都成功,失敗都失敗,狀態保持一致。
異步:是不需要等待被依賴的任務完成,只是通知被依賴的任務要完成什么工作,依賴的任務也立即執行,只要自己完成了任務就算完成了。所以它是不可靠的任務序列。
通俗一點講:同步 比喻成一個人去書店買書,問書店老板有沒有這本書,書店老板給你找,而在這個過程中,你是一直在書店等待書店老板返回的結果。# 是一種效率低下的方式。
異步:讓老板先找書,自己先去工作,找到書了給自己打電話,再來拿書。# 這是一種效率高的方式。
同步阻塞的方式:效率低下,只能等待返回結果,干不了其他事情
異步阻塞的方式:效率更高,在等待返回結果先干別的事情,返回結果再來干這件事。
5、如何開啟進程
一、multiprocess模塊:多功能的意思
分為四部分:創建進程部分,進程同步部分,進程池部分,進程之間數據共享。
二、multiprocess.process模塊
process模塊是一個創建進程的模塊,借助這個模塊,就可以完成進程的創建。
代碼:
from multiprocessing import Process
def write():
with open('aaa','w') as f:
f.write('hello')
# 一個進程必須至少有一個線程
# 在winds中,開啟進程必須寫在__main__里面
if __name__ == '__main__':
p = Process(target=weite)
# 開啟進程必須調用start方法
p.start()
6、process類的參數
參數介紹:
1.group參數未使用,值始終為None
2.target表示調用對象,即子進程要執行的任務
3.args表示調用對象的位置參數元祖,args=(1,2,'meng')
4.kwargs表示調用對象的字典,kwargs={'name':'meng','age':18}
5.naem為子進程的名稱
from multiprocessing import Process
def task(age, name):
# with open('aaa', 'w') as f:
# f.write('hello')
print(name)
print(age)
# 一個進程中必須至少有一個線程
# 在wins中,開啟進程必須寫在__main__里面
if __name__ == '__main__':
"""
target=None, name=None, args=(), kwargs={},
*, daemon=None
"""
# p = Process(target=write, name='meng')
# p = Process(target=task, args=('meng', 18))
p = Process(target=task, kwargs={'name': 'meng', 'age': 18})
# 開啟進程必須調用start方法
p.start()
print(p.name) # 進程名:Process-1
7、process類的方法
方法:
1.p.start():啟動進程,並調用該子進程中的p.run()
2.p.run():進程啟動時運行的方法,正是它去調用target指定的函數、
3.p.terminate():強制終止進程p,不會進行任何操作。
4.p.is_alive():如果p仍在運行,返回True
5.p.join():等子進程運行完在執行,注意:p.join只能在statr開啟的進程,不能在run開啟的進程
代碼:
from multiprocessing import Process
import time
def task(age, name):
# with open('aaa', 'w') as f:
# f.write('hello')
print(name)
# print(age)
# 一個進程中必須至少有一個線程
# 在wins中,開啟進程必須寫在__main__里面
if __name__ == '__main__':
p = Process(target=task, kwargs={'name': 'meng', 'age': 18})
# 開啟進程必須調用start方法
p.start()
# # p.run() # 也可以開啟進程
# print(p.is_alive()) # 判斷這個進程是否存活,結果True
# time.sleep(2)
# p.terminate() # 殺死這個進程
print(p.is_alive()) # 結果False
p.join() # 等待子進程執行完畢再執行
'''
子進程
父進程
'''
print('=====>')
8、process類的屬性介紹
屬性介紹:
1.p.daemon:默認值為False,如果設為True,代表p為后台運行的守護進程,當p的父進程終止時,p也隨之終止,並且設定為True后,p不能創建自己的新進程,必須在p.start()之前設置
2.p.name:進程的名稱
3.p.pid:進程的pid
4.p.exitcode:進程在運行時為None、如果為–N,表示被信號N結束(了解即可)
5.p.authkey:進程的身份驗證鍵,默認是由os.urandom()隨機生成的32字符的字符串。這個鍵的用途是為涉及網絡連接的底層進程間通信提供安全性,這類連接只有在具有相同的身份驗證鍵時才能成功(了解即可)
代碼:
from multiprocessing import Process
import time
def task(age, name):
# with open('aaa', 'w') as f:
# f.write('hello')
# print(name)
# print(age)
time.sleep(2)
print(name)
# 一個進程中必須至少有一個線程
# 在wins中,開啟進程必須寫在__main__里面
if __name__ == '__main__':
p = Process(target=task, kwargs={'name': 'meng', 'age': 18})
'''
守護進程:父進程執行完畢,子進程也立即結束
'''
p.daemon = True # 強調:一定要放在start之前
# 正常輸出Process-1,meng。 加上p.demon不會運行meng,直接運行print(p.name)
# 開啟進程必須調用start方法
p.start()
print(p.pid) # 可以查看子進程的pid
print(p.name) # 進程名:Process-1
9、獲取進程id號
代碼:
from multiprocessing import Process
import os
import time
def task(name,age):
print('子進程的id號:%s'% os.getpid())
print('父進程的id號:%s'% os.getppid())
time.sleep(10)
if __name__ == '__main__':
p = Process(target = task,kwargs={'name':'meng','age':18})
p.start()
print(p.pid)
print('main里的主進程的id號:%s'% os.getpid())
print('main里的父進程的id號:%s'% os.getppid())
time.sleep(10)
print('====>')
輸出結果:可以打開資源管理器看看
33540
main里的主進程的id號:32680
main里的父進程的id號:28896
子進程的id號:33540
父進程的id號:32680
====>
10、開啟多進程
代碼:
from multiprocessing import Process
import time
import os
def task(i):
time.sleep(2)
print(i)
if __name__ == '__main__':
l = []
for i in range(10):
p = Process(target=task,args=(i,))
p.start()
l.append(p)
for j in l:
j.join()
# 開啟10次進程