Python之進程間通信(PIC)

進程間通信(IPC

    1. 必要性: 進程間空間獨立,資源不共享,此時在需要進程間數據傳輸時就需要特定的手段進行數據通信。

    2. 常用進程間通信方法

管道 消息隊列 共享內存 信號 信號量 套接字

    管道通信(Pipe)

          1. 通信原理

               在內存中開闢管道空間,生成管道操作對象,多個進程使用同一個管道對象進行讀寫即可實現通信

          2. 實現方法

from multiprocessing import Pipe

fd1,fd2 = Pipe(duplex = True)

功能: 創建管道

參數:默認表示雙向管道

           如果爲False 表示單向管道

返回值:表示管道兩端的讀寫對象

               如果是雙向管道均可讀寫

               如果是單向管道fd1只讀 fd2只寫

fd.recv()

功能 : 從管道獲取內容

返回值:獲取到的數據

fd.send(data)

功能: 向管道寫入內容

參數: 要寫入的數據

示例:

# 管道通信
import os
import time
from multiprocessing import Pipe, Process


def fun(fd, name):
    time.sleep(2)
    fd.send({name: os.getpid()})


if __name__ == '__main__':
    #  創建雙向管道
    fd1, fd2 = Pipe(duplex=True)
    jobs = []

    # 生成三個進程給管道寫入信息
    for i in range(3):
        p = Process(target=fun, args=(fd1, i))
        jobs.append(p)
        p.start()

    # 從管道中讀取數據
    for i in range(3):
        data = fd2.recv()
        print(data)

    for i in jobs:
        i.join()

    消息隊列

        1.通信原理

             在內存中建立隊列模型,進程通過隊列將消息存入,或者從隊列取出完成進程間通信。

        2. 實現方法

from multiprocessing import Queue

q = Queue(maxsize=0)

功能: 創建隊列對象

參數:最多存放消息個數

返回值:隊列對象

q.put(data,[block,timeout])

功能:向隊列存入消息

參數:data 要存入的內容

           block 設置是否阻塞 False爲非阻塞,默認爲True,阻塞

           timeout 超時檢測

q.get([block,timeout])

功能:從隊列取出消息

參數:block 設置是否阻塞 False爲非阻塞

           timeout 超時檢測

返回值: 返回獲取到的內容

q.full()

判斷隊列是否爲滿

q.empty()

判斷隊列是否爲空

q.qsize()

獲取隊列中消息個數

q.close()

關閉隊列

示例:

# 消息隊列通信

from multiprocessing import Queue, Process
from time import sleep
from random import randint


def request(q):
    for i in range(20):
        x = randint(0, 100)
        y = randint(0, 100)
        # 默認爲阻塞,當管道數據滿時,會一直等待別的線程取走數據纔會存入新數據
        # 如果設置非阻塞,當管道數據滿時會拋出異常:exception Queue.Full
        q.put((x, y))


def handle(q):
    while True:
        sleep(0.5)
        try:
            # 默認爲阻塞,當管道數據爲空時,會一直等待別的線程寫入數據纔會取出新數據
            # 如果設置非阻塞,當管道數據爲空時會拋出異常:exception Queue.Empty
            x, y = q.get(timeout=3)  # 最多等待3秒,超時會拋異常
        except:
            break
        else:
            print("%d + %d = %d" % (x, y, (x + y)))


if __name__ == '__main__':
    # 創建隊列對象,可存放三個數據
    q = Queue(3)
    # 創建一個進程把數據存入隊列(20個元組)
    p1 = Process(target=request, args=(q,))
    # 創建一個進程從隊列中取值
    p2 = Process(target=handle, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

 

    共享內存

        1. 通信原理

            在內中開闢一塊空間,進程可以寫入內容和讀取內容完成通信,但是每次寫入內容會覆蓋之前內容

        2. 實現方法

            數據類型

from multiprocessing import Value,Array

obj = Value(ctype,data)

功能 : 開闢共享內存

參數 : ctype 表示共享內存空間類型 'i' 'f' 'c'

             data 共享內存空間初始數據

返回值:共享內存對象

obj.value 對該屬性的修改查看即對共享內存讀寫

obj = Array(ctype,data)

功能: 開闢共享內存空間

參數: ctype 表示共享內存數據類型

data 整數則表示開闢空間的大小,其他數據類型表示開闢空間存放的初始化數據

返回值:共享內存對象

Array共享內存讀寫: 通過遍歷obj可以得到每個值,直接可以通過索引序號修改任意值。

* 可以使用obj.value直接打印共享內存中的字節串

示例1:Value

from multiprocessing import Process, Value
import time
import random


# 操作共享內存
def man(money):
    for i in range(30):
        time.sleep(0.2)
        money.value += random.randint(1, 1000)


def girl(money):
    for i in range(30):
        time.sleep(0.15)
        money.value -= random.randint(100, 800)


if __name__ == '__main__':
    # 創建共享內存數據
    money = Value('i', 5000)
    # 兩個線程共同影響共享內存
    p1 = Process(target=man, args=(money,))
    p2 = Process(target=girl, args=(money,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print("剩餘:", money.value)

示例2:Array

from multiprocessing import Process, Array


# 創建共享內存
# 共享內存開闢5個整型列表空間
# shm = Array('i', 5) 參數2整數代表空間大小


def fun(shm):
    # 共享內存對象可迭代
    for c in shm:
        print(c)

    # 修改內存空間數據
    shm[1] = b'o'


if __name__ == '__main__':
    # shm = Array('i', [1, 2, 3]) 參數2直接傳入數據
    shm = Array('c', b'hello')
    p1 = Process(target=fun, args=(shm,))
    p1.start()
    p1.join()

    # 迭代取值
    for i in shm:
        print(i)

    # 一次性取值
    print(shm.value)

   

    信號量(信號燈集)

        1. 通信原理

             給定一個數量的信號對多個進程可見。多個進程都可以操作該信號量增減,並根據數量值決定自己的行爲。

        2. 實現方法

from multiprocessing import Semaphore

sem = Semaphore(num)

功能 : 創建信號量對象

參數 : 信號量的初始值

返回值 : 信號量對象

sem.acquire()

將信號量減1 當信號量爲0時阻塞

sem.release()

將信號量加1

sem.get_value()

獲取信號量數量

示例:

"""
信號量演示
注意: 信號量相當於資源,多個進程對數量進行控制
"""

from multiprocessing import Process, Semaphore
from time import sleep
import os


# 任務函數
def handle(s):
    print("現存信號:", s.get_value())
    s.acquire()  # 執行任務必須消耗一個信號量
    print("開始執行任務:", os.getpid())
    sleep(2)
    print("執行任務結束:", os.getpid())
    s.release()  # 增加一個信號量


if __name__ == '__main__':
    # 創建信號量
    sem = Semaphore(3)

    # 創建5個線程,三個信號肯定不夠,前三個線程將信號量兼爲0,
    # 後兩個線程執行acquire時會魚洞阻塞,
    # 等待前三個中有人將信號還回纔可以繼續執行
    for i in range(5):
        p = Process(target=handle, args=(sem,))
        p.start()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章