併發編程-守護進程-互斥鎖

守護進程

主進程建立守護進程(子進程)python

那麼主進程就是被守護進程安全

  • 守護進程會在主進程代碼執行結束後就終止
  • 守護進程內沒法再開啓子進程,不然拋出異常:AssertionError: daemonic processes are not allowed to have children

注意:進程之間是相互獨立的,主進程代碼運行結束,守護進程隨即終止.併發

from multiprocessing import Process
import time

def task():
    print('sub start')
    print('sub over')


if __name__ == '__main__':
    p =Process(target=task)
    p.daemon = True  # 將這個進程設置成子進程,必須放在p.start()前面
    p.start()
    print('parent start')
    time.sleep(1)   # 這裏加延時,就是爲了讓子進程運行完畢,不然,就會出現子進程(守護進程)尚未運行徹底,主程序(被守護進程)就已經運行完並結束代碼了
    print('parent over')
    
# 若是沒有在主程序這裏加延時,則不會打印子進程,由於在操做系統開啓子進程時,主程序代碼已經運行完畢.   
parent start
sub start  
sub over
parent over

進程安全問題

由於子進程的內存時相互隔離的,因此進程之間數據不共享;若是多個在子進程同時訪問同一個文件,或者打印同一個終端,那麼就會帶來競爭,競爭帶來的結果就是錯亂,這個就是進程安全問題.app

這裏進程1和進程2,之因此把範圍放這麼大,是爲了能顯示出問題打印ui

from multiprocessing import Process

def task1():
    for i in range(10000):
        print('sub1 run')
        print('sub1  over')


def task2():
    for i in range(10000):
        print('sub2 run')
        print('sub2  over')


if __name__ == '__main__':
    p1 = Process(target=task1)
    p2 = Process(target=task2)

    p1.start()
    p2.start()

    
sub1  over
sub2  over
sub1 run
sub2 run
sub1  over
sub2  over

互斥鎖(進程同步)

什麼是互斥鎖?操作系統

​ 互相排斥的鎖code

原理:隊列

​ 就是將要操做公共資源的代碼鎖起來 以保證同一時間只能有一個進程在執行這部分代碼進程

進程之間數據不共享,可是共享同一套文件系統,同時訪問同一個文件,或者打印同一個終端,那麼就會產生競爭,競爭帶來的結果就是錯亂,如何控制,就是加鎖處理ip

爲了解決上面出現由於子進程競爭而出現的進程安全問題,爲了解決這個問題,咱們用到了互斥鎖.

from multiprocessing import Process,Lock

def task1(mutex):
    mutex.acquire()
    for i in range(10000):
        print('sub1 run')
        print('sub1  over')
        
    mutex.release()

def task2(mutex):
    mutex.acquire()
    for i in range(10000):
        print('sub2 run')
        print('sub2  over')
    mutex.release()


if __name__ == '__main__':
    mutex = Lock()
    p1 = Process(target=task1,args=(mutex,))
    p2 = Process(target=task2,args=(mutex,))

    p1.start()
    p2.start()

鎖的原理

def task1():
    global lock
    if lock == False:
        lock = True
        open("aaa.txt","wt")
        lock = False


def task2():
    global lock
    if lock == False:
        lock = True
        open("aaa.txt","wt")
        lock = False

從這能夠看出,鎖並非把數據鎖住不讓用,而是讓代碼不執行.

manager 管理器

多個子進程同時讀寫一個共享文件,雖然加了鎖,但有時也會形成文件錯亂問題,由於子進程之間數據不互通,即數據不一樣步.那麼咱們就須要建立一個同步通道

from multiprocessing import Process,Manager,Lock
import time

def task(data,lock):
    lock.acquire()
    num = data[0]
    time.sleep(0.2)
    data[0] = num -1
    lock.release()


if __name__ == '__main__':
    d = [100]
    m = Manager()  # 建立一個管理器
    sync_list = m.list(d)  # 讓管理器建立一個進程同步的列表(也能夠是字典等)

    lock = Lock() # 建立一個鎖

    ps = []
    for i in range(10):
        p = Process(target=task,args=(sync_list,lock))
        p.start()
        ps.append(p)

    for p in ps:p.join()

    print(d)
    print(sync_list)
    
sub over
sub over
sub over
sub over
sub over
sub over
sub over
sub over
sub over
sub over
[100]
[90]

總結:

加鎖能夠保證多個進程修改同一塊數據時,同一時間只能有一個任務能夠進行修改,即將併發改爲串行,保證了數據安全,可是犧牲了速度.

雖然能夠用文件共享數據實現進程間通訊,但問題是:

  • 效率低:共享數據是基於文件,而文件是在硬盤上
  • 須要本身加鎖處理

這種方式適合交互不頻繁,數據量大的狀況,

對於交互頻繁,數據量小的狀況不合適,所以咱們用另一種解決方案:IPC(進程間通訊)--隊列+管道

隊列

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

隊列是先進先出

from multiprocessing import Queue

q = Queue(2)  # 建立隊列,而且同時只能存儲兩個元素,若是不寫,默認爲無限大
q.put(1)  # 將數據存入管道
q.put(2)
# q.put(3,block=False,timeout=3)  # block=True表示阻塞,默認爲True; timeout=3表示等待延時3s,默認爲None;
                               # 當容器中沒有位置了就阻塞,等待3秒,在這個時間段有人從管道里面取走一個元素,
                               # 那麼元素3就會存入進去,不然就會拋出錯誤 queue.Full

print(q.get())  # get 是將數據取出來 而且是先進先出
print(q.get())
# print(q.get(block=True,timeout=3)) # 默認是阻塞,直到有人存入元素, 跟存入同樣.
相關文章
相關標籤/搜索