1. 程式人生 > >python之多進程

python之多進程

col lse 樹形結構 並發 作用 自定義 http 自己的 兩種

一.概述

1.什麽是進程

進程:正在進行的一個過程或者說一個任務。而負責執行任務則是cpu。

2.進程與程序區別

程序僅僅只是一堆代碼而已,而進程指的是程序的運行過程。

3.並發與並行

無論是並行還是並發,在用戶看來都是‘同時‘運行的,不管是進程還是線程,都只是一個任務而已,真是幹活的是cpu,cpu來做這些任務,而一個cpu同一時刻只能執行一個任務。

並發:是偽並行,即看起來是同時運行。單個cpu+多道技術就可以實現並發。

並行:同時運行,只有具備多個cpu才能實現並行。

4.進程的層次結構

無論UNIX還是windows,進程只有一個父進程,不同的是:

在UNIX中所有的進程,都是以init進程為根,組成樹形結構。父子進程共同組成一個進程組,這樣,當從鍵盤發出一個信號時,該信號被送給當前與鍵盤相關的進程組中的所有成員。

在windows中,沒有進程層次的概念,所有的進程都是地位相同的,唯一類似於進程層次的暗示,是在創建進程時,父進程得到一個特別的令牌(稱為句柄),該句柄可以用來控制子進程,但是父進程有權把該句柄傳給其他子進程,這樣就沒有層次了。

5.進程的狀態

在兩種情況下會導致一個進程在邏輯上不能運行:

1.進程掛起是自身原因,遇到I/O阻塞,便要讓出CPU讓其他進程去執行,這樣保證CPU一直在工作。

2.與進程無關,是操作系統層面,可能會因為一個進程占用時間過多,或者優先級等原因,而調用其他的進程去使用CPU。

因而一個進程由三種狀態

技術分享圖片

二.進程的使用

1.multiprocessing模塊介紹

python中的多線程無法利用多核優勢,如果想要充分地使用多核CPU的資源(os.cpu\_count\(\)查看),在python中大部分情況需要使用多進程。

Python提供了multiprocessing。 multiprocessing模塊用來開啟子進程,並在子進程中執行我們定制的任務(比如函數),該模塊與多線程模塊threading的編程接口類似。multiprocessing模塊的功能眾多:支持子進程、通信和共享數據、執行不同形式的同步,>提供了Process、Queue、Pipe、Lock等組件。

需要再次強調的一點是:與線程不同,進程沒有任何共享狀態,進程修改的數據,改動僅限於該進程內。

2.process類介紹

創建進程的類:

Process([group [, target [, name [, args [, kwargs]]]]])

由該類實例化得到的對象,可用來開啟一個子進程

強調: 1. 需要使用關鍵字的方式來指定參數

    2. args指定的為傳給target函數的位置參數,是一個元組形式,必須有逗號

參數介紹

group參數未使用,值始終為None
target表示調用對象,即子進程要執行的任務
args表示調用對象的位置參數元組,args=(1,2,egon,)
kwargs表示調用對象的字典,kwargs={name:egon,age:18}
name為子進程的名稱

方法介紹:

p.start():啟動進程,並調用該子進程中的p.run() 
p.run():進程啟動時運行的方法,正是它去調用target指定的函數,我們自定義類的類中一定要實現該方法  
p.terminate():強制終止進程p,不會進行任何清理操作,如果p創建了子進程,該子進程就成了僵屍進程,使用該方法需要特別小心這種情況。如果p還保存了一個鎖那麽也將不會被釋放,進而導致死鎖
p.is_alive():如果p仍然運行,返回True
p.join([timeout]):主線程等待p終止(強調:是主線程處於等的狀態,而p是處於運行的狀態)。timeout是可選的超時時間。

屬性介紹:

p.daemon:默認值為False,如果設為True,代表p為後臺運行的守護進程,當p的父進程終止時,p也隨之終止,並且設定為True後,p不能創建自己的新進程,必須在p.start()之前設置
p.name:進程的名稱
p.pid:進程的pid

3.開啟進程的兩個方法

方法一

from multiprocessing import Process
import time


def task(name):
    print(%s is running %name)
    time.sleep(3)
    print(%s is done %name)


if __name__ == __main__:
    # Process(target=task, kwargs={‘name‘:‘子進程1‘})
    p = Process(target=task, args=(子進程1,))
    p.start()  # 僅僅只是發送一個信號

    print()

方法二

from multiprocessing import Process
import time


class MyProcss(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print(%s is running % self.name)
        time.sleep(3)
        print(%s is done % self.name)


if __name__ == __main__:
    p = MyProcss(子進程1)
    p.start()

    print()

4.join方法和守護進程

a.join

在主進程運行過程中如果想並發地執行其他的任務,我們可以開啟子進程,此時主進程的任務與子進程的任務分兩種情況。

情況一:在主進程的任務與子進程的任務彼此獨立的情況下,主進程的任務先執行完畢後,主進程還需要等待子進程執行完畢,然後統一回收資源。

情況二:如果主進程的任務在執行到某一個階段時,需要等待子進程執行完畢後才能繼續執行,就需要有一種機制能夠讓主進程檢測子進程是否運行完畢,在子進程執行完畢後才繼續執行,否則一直在原地阻塞,這就是join方法的作用。

from multiprocessing import Process
import time,os


def task(name):
    print(%s is running,parent id is %s % (os.getpid(), os.getppid()))
    time.sleep(3)
    print(%s is done,parent id is %s % (os.getpid(), os.getppid()))


if __name__ == __main__:
    p = Process(target=task, args=(子進程1,))
    p.start()  # 僅僅只是發送一個信號

    p.join()  # 等待子進程結束
    print(, os.getpid(), os.getppid())

b.守護進程

主進程創建子進程,然後將該進程設置成守護自己的進程,守護進程就好比崇禎皇帝身邊的老太監,崇禎皇帝已死老太監就跟著殉葬了。

關於守護進程需要強調兩點:

其一:守護進程會在主進程代碼執行結束後就終止

其二:守護進程內無法再開啟子進程,否則拋出異常:AssertionError: daemonic processes are not allowed to have children

適用場景:

如果我們有兩個任務需要並發執行,那麽開一個主進程和一個子進程分別去執行就ok了,如果子進程的任務在主進程任務結束後就沒有存在的必要了,那麽該子進程應該在開啟前就被設置成守護進程。主進程代碼運行結束,守護進程隨即終止。

from multiprocessing import Process
import time


def task(name):
    print(%s is running % name)
    time.sleep(2)


if __name__ == __main__:
    p = Process(target=task, args=(子進程1,))
    p.daemon = True  # 子進程還沒啟動就隨主關閉
    p.start()
    print()

5.互斥鎖

進程之間數據不共享,但是共享同一套文件系統,所以訪問同一個文件,或同一個打印終端,是沒有問題的,而共享帶來的是競爭,競爭帶來的結果就是錯亂,如下代碼:

#並發運行,效率高,但競爭同一打印終端,帶來了打印錯亂
from multiprocessing import Process
import os,time
def work(): print(%s is running %os.getpid()) time.sleep(2) print(%s is done %os.getpid())
if __name__ == __main__: for i in range(3): p=Process(target=work) p.start()

加鎖處理來控制輸出

#由並發變成了串行,犧牲了運行效率,但避免了競爭
from multiprocessing import Process,Lock
import os,time
def work(lock): lock.acquire() #加鎖 print(%s is running %os.getpid()) time.sleep(2) print(%s is done %os.getpid()) lock.release() #釋放鎖

if __name__ == __main__: lock=Lock() for i in range(3): p=Process(target=work,args=(lock,)) p.start()

6.隊列

進程彼此之間互相隔離,要實現進程間通信(IPC),multiprocessing模塊支持兩種形式:隊列和管道,這兩種方式都是使用消息傳遞的。

from multiprocessing import Queue

q = Queue(3)

q.put(hello)
q.put({a: 1})
q.put([3, 3, 3])
print(q.full())
# q.put(4) #再放就阻塞住了

print(q.get())
print(q.get())
print(q.get())
print(q.empty())  # 空了
# print(q.get()) #再取就阻塞住了

python之多進程