二十五、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()
发布了39 篇原创文章 · 获赞 10 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/chiaotien/article/details/104490616