意義:充分利用計算機的資源提升程序的運行效率python
定義:經過應用程序利用計算機多個核心,達到同時執行多個任務的目的linux
實施方案: 多進程、多線程
編程
並行:多個計算機核心並行的同時處理多個任務多線程
併發:內核在多個任務間不斷切換,達到好像內核在同時處理多個任務的運行效果併發
進程:程序在計算機中運行一次的過程app
程序:是一個可執行文件,是靜態的,佔有磁盤,不佔有計算機運行資源dom
進程:進程是一個動態的過程描述,佔有CPU內存等計算機資源的,有必定的生命週期async
* 同一個程序的不一樣執行過程是不一樣的進程,由於分配的計算機資源等均不一樣函數
父子進程 : 系統中每個進程(除了系統初始化進程)都有惟一的父進程,能夠有0個或多個子進
程。父子進程關係便於進程管理。ui
CPU時間片:若是一個進程在某個時間點被計算機分配了內核,咱們稱爲該進程在CPU時間片上。
PCB(進程控制塊):存放進程消息的空間
進程ID(PID):進程在操做系統中的惟一編號,由系統自動分配
進程信息包括:進程PID,進程佔有的內存位置,建立時間,建立用戶. . . . . . . .
進程特徵:
進程的狀態
一、三態
二、五態(增長新建態和終止態)
查看進程樹: pstree
查看父進程PID: ps -ajx
linux查看進程命令: ps -aux
有一列爲STAT爲進程的狀態
D 等待態 (不可中斷等待)(阻塞)
S 等待態 (可中斷等待)(睡眠)
T 等待態 (暫停狀態)
R 運行態 (就緒態運行態)
Z 殭屍態
+ 前臺進程(能在終端顯示出現象的)
< 高優先級
N 低優先級
l 有多線程的
s 會話組組長
pid = os.fork()
功能:建立一個子進程
返回值:建立成功在原有的進程中返回子進程的PID,在子進程中返回0;建立失敗返回一個負數
父子進程一般會根據fork返回值的差別選擇執行不一樣的代碼(使用if結構)
import os from time import sleep pid = os.fork() if pid < 0: print("建立進程失敗") #子進程執行部分 elif pid == 0: print("新進程建立成功") #父進程執行部分 else: sleep(1) print("原來的進程") print("程序執行完畢") # 新進程建立成功 # 原來的進程 # 程序執行完畢
父子進程的變量域
import os from time import sleep a = 1 pid = os.fork() if pid < 0: print("建立進程失敗") elif pid == 0: print("子進程") print("a = ",a) a = 10000 print("a = ",a) else: sleep(1) print("父進程") print("parent a :",a) # a = 1 # 子進程 # a = 1 # a = 10000 # 父進程 # parent a : 1
os.getpid() 獲取當前進程的PID號
返回值:返回PID號
os.getppid() 獲取父類進程的進程號
返回值:返回PID號
import os pid = os.fork() if pid < 0: print("Error") elif pid == 0: print("Child PID:", os.getpid()) # 26537 print("Get parent PID:", os.getppid()) # 26536 else: print("Get child PID:", pid) # 26537 print("Parent PID:", os.getpid()) # 26536
os._exit(status) 退出進程
參數:進程的退出狀態 整數
sys.exit([status]) 退出進程
參數:默認爲0 整數則表示退出狀態;符串則表示退出時打印內容
sys.exit([status])能夠經過捕獲SystemExit異常阻止退出
import os,sys # os._exit(0) # 退出進程 try: sys.exit("退出") except SystemExit as e: print("退出緣由:",e) # 退出緣由: 退出
父進程先於子進程退出,此時子進程就會變成孤兒進程
孤兒進程會被系統指定的進程收養,即系統進程會成爲該孤兒進程新的父進程。孤兒進程退出時該父進程會處理退出狀態
子進程先與父進程退出,父進程沒有處理子進程退出狀態,此時子進程成爲殭屍進程
殭屍進程已經結束,可是會滯留部分PCB信息在內存,大量的殭屍會消耗系統資源,應該儘可能避免
pid, status = os.wait()
功能:在父進程中阻塞等待處理子進程的退出
返回值: pid 退出的子進程的PID號
status 子進程的退出狀態
import os, sys pid = os.fork() if pid < 0: print("Error") elif pid == 0: print("Child process", os.getpid()) # Child process 27248 sys.exit(1) else: pid, status = os.wait() # 阻塞等待子進程退出 print("pid : ", pid) # pid : 27248 # 還原退出狀態 print("status:", os.WEXITSTATUS(status)) # status: 1 while True: pass
import os from time import sleep def fun1(): sleep(3) print("第一件事情") def fun2(): sleep(4) print("第二件事情") pid = os.fork() if pid < 0: print("Create process error") elif pid == 0: # 子進程 pid0 = os.fork() # 建立二級進程 if pid0 < 0: print("建立二級進程失敗") elif pid0 == 0: # 二級子進程 fun2() # 作第二件事 else: # 二級進程 os._exit(0) # 二級進程退出 else: os.wait() fun1() # 作第一件事 # 第一件事情 # 第二件事情
原理: 子進程退出時會發送信號給父進程,若是父進程忽略子進程信號, 則系統就會自動處理子進程退出。
方法: 使用signal模塊在父進程建立子進程前寫以下語句 :
import signal
signal.signal(signal.SIGCHLD,signal.SIG_IGN)
特色 : 非阻塞,不會影響父進程運行。能夠處理全部子進程退出
步驟:
p = multiprocessing.Process(target, [name], [args], [kwargs])
建立進程對象
參數:
p.start()
功能 : 啓動進程 自動運行terget綁定函數。此時進程被建立
p.join([timeout])
功能: 阻塞等待子進程退出,最後回收進程
參數: 超時時間
multiprocessing的注意事項:
import multiprocessing as mp from time import sleep import os a = 1 def fun(): sleep(2) print("子進程事件",os.getpid()) global a a = 10000 print("a = ",a) p = mp.Process(target = fun) # 建立進程對象 p.start() # 啓動進程 sleep(3) print("這是父進程") p.join() # 回收進程 print("parent a:",a) # 子進程事件 5434 # a = 10000 # 這是父進程 # parent a: 1 Process(target)
p.name 進程名稱
p.pid 對應子進程的PID號
p.is_alive() 查看子進程是否在生命週期
p.daemon 設置父子進程的退出關係
若是等於True則子進程會隨父進程的退出而結束,就不用使用 join(),必需要求在start()前設置
引言:若是有大量的任務須要多進程完成,而任務週期又比較短且須要頻繁建立。此時可能產生大量進程頻繁建立銷燬的狀況,消耗計算機資源較大,這個時候就須要進程池技術
進程池的原理:建立必定數量的進程來處理事件,事件處理完進程不退出而是繼續處理其餘事件,直到全部事件全都處理完畢統一銷燬。增長進程的重複利用,下降資源消耗。
1.建立進程池,在池內放入適當數量的進程
from multiprocessing import Pool
Pool(processes) 建立進程池對象
2.將事件封裝函數,放入到進程池
pool.apply_async(fun,args,kwds) 將事件放入進程池執行
參數:
返回值 :
3.關閉進程池
pool.close() 關閉進程池,沒法再加入事件
4.回收進程
pool.join() 回收進程池
from multiprocessing import Pool from time import sleep,ctime pool = Pool(4) # 建立進程池 # 進程池事件 def worker(msg): sleep(2) print(msg) return ctime() # 向進程池添加執行事件 for i in range(4): msg = "Hello %d"%i # r 表明func事件的一個對象 r = pool.apply_async(func=worker,args=(msg,)) pool.close() # 關閉進程池 pool.join() # 回收進程池 # Hello 3 # Hello 2 # Hello 0 # Hello 1
因爲進程間空間獨立,資源沒法共享,此時在進程間通訊就須要專門的通訊方法。
進程間通訊方法 : 管道 消息隊列 共享內存 信號信號量 套接字
通訊原理:在內存中開闢管道空間,生成管道操做對象,多個進程使用同一個管道對象進行讀寫便可實現通訊
from multiprocessing import Pipe
fd1, fd2 = Pipe(duplex = True)
fd.recv()
fd.send(data)
注意:
from multiprocessing import Pipe, Process fd1, fd2 = Pipe() # 建立管道,默認雙向管道 def fun1(): data = fd1.recv() # 從管道獲取消息 print("管道2傳給管道1的數據", data) inpu = "跟你說句悄悄話" fd1.send(inpu) def fun2(): fd2.send("肥水不流外人天") data = fd2.recv() print("管道1傳給管道2的數據", data) p1 = Process(target=fun1) P2 = Process(target=fun2) p1.start() P2.start() p1.join() P2.join() # 管道2傳給管道1的數據 肥水不流外人天 # 管道1傳給管道2的數據 跟你說句悄悄話
從內存中開闢隊列結構空間,多個進程能夠向隊列投放消息,在取出來的時候按照先進先出順序取出
q = Queue(maxsize = 0)
建立隊列對象
q.put(data,[block,timeout])
向隊列中存入消息
返回值:返回獲取的消息
q.get([block,timeout])
從隊列取出消息
q.full() 判斷隊列是否爲滿
q.empty() 判斷隊列是否爲空
q.qsize() 判斷當前隊列有多少消息
q.close() 關閉隊列
from multiprocessing import Process, Queue from time import sleep from random import randint # 建立消息隊列 q = Queue(3) # 請求進程 def request(): for i in range(2): x = randint(0, 100) y = randint(0, 100) q.put((x, y)) # 處理進程 def handle(): while True: sleep(1) try: x, y = q.get(timeout=2) except: break else: print("%d + %d = %d" % (x, y, x + y)) p1 = Process(target=request) p2 = Process(target=handle) p1.start() p2.start() p1.join() p2.join() # 12 + 61 = 73 # 69 + 48 = 117
在內存中開闢一段空間,存儲數據,對多個進程可見,每次寫入共享內存中的數據會覆蓋以前的內容,效率高,速度快
from multiprocessing import Value, Array
obj = Value(ctype,obj)
功能:開闢共享內存空間
參數:ctype 字符串 要轉變的c的數據類型,對比類型對照表
obj 共享內存的初始化數據
返回:共享內存對象
from multiprocessing import Process,Value import time from random import randint # 建立共享內存 money = Value('i', 5000) # 修改共享內存 def man(): for i in range(30): time.sleep(0.2) money.value += randint(1, 1000) def girl(): for i in range(30): time.sleep(0.15) money.value -= randint(100, 800) m = Process(target=man) g = Process(target=girl) m.start() g.start() m.join() g.join() print("一月餘額:", money.value) # 獲取共享內存值 # 一月餘額: 4264
obj = Array(ctype,obj)
功能:開闢共享內存
參數:ctype 要轉化的c的類型
obj 要存入共享的數據
若是是列表 將列表存入共享內存,要求數據類型一致
若是是正整數 表示開闢幾個數據空間
from multiprocessing import Process, Array # 建立共享內存 # shm = Array('i',[1,2,3]) # shm = Array('i',3) # 表示開闢三個空間的列表 shm = Array('c',b"hello") #字節串 def fun(): # 共享內存對象可迭代 for i in shm: print(i) shm[0] = b'H' p = Process(target=fun) p.start() p.join() for i in shm: # 子進程修改,父進程中也跟着修改 print(i) print(shm.value) # 打印字節串 b'Hello'
通訊原理:給定一個數量對多個進程可見。多個進程均可以操做該數量增減,並根據數量值決定本身的行爲。
from multiprocessing import Semaphore
sem = Semaphore(num)
建立信號量對象
sem.acquire() 將信號量減1 當信號量爲0時阻塞
sem.release() 將信號量加1
sem.get_value() 獲取信號量數量
from multiprocessing import Process, Semaphore sem = Semaphore(3) # 建立信號量,最多容許3個任務同時執行 def rnewu(): sem.acquire() # 每執行一次減小一個信號量 print("執行任務.....執行完成") sem.release() # 執行完成後增長信號量 for i in range(3): # 有3我的想要執行任務 p = Process(target=rnewu) p.start() p.join()