『踩坑记录』进程间通信方式选择不当导致进程阻塞

本篇博客主要介绍Python中使用了不恰当的进程间通信方式导致进程阻塞的解决方案。

最近,帮本科生辅导竞赛,遇到了一个问题,项目中用到了多进程,涉及到多进程,自然少不了进程间通信。
大概场景为:一个进程需要将数据传给另一个进程。最开始使用的进程间通信方式为Queue初始容量为10个元素。但是当时问题是,生产数据的进程运行速度比消费数据的进程快,导致Queue很快被填满导致生产数据的进程阻塞。但是这里生产数据的进程还有综合显示的功能,导致显示效果一顿一顿的,效果非常差。

我们来简单模拟一下上述问题

from multiprocessing import Process, Queue
import time

# 生产者
def producer(q_production):
    num = 1
    while True:
        print("q_production")
        q_production.put(num)
        num = num + 1

# 消费者
def consumer(q_consume):
    while True:
        try:
            num = q_consume.get()
        except:
            num = 0
            pass

        print("q_consume: %d" % num)
        # 手动延时1s,让消费者比生产者慢
        time.sleep(1)

if __name__ == "__main__":
	# 容量为10
    q = Queue(10)

    test1 = Process(target = producer, args = (q, ))
    test1.start()

    test2 = Process(target = consumer, args = (q, ))
    test2.start()

我们来看一下效果
在这里插入图片描述
可以看到效果为生产者刚开始迅速将队列填满填满之后生产者进程就阻塞了,只有在队列中有空位置的时候才可以向其中添加数据

有什么解决方法呢
方法一
我们可以使用Queue的put_nowait()get_nowait()这两个方法都是非阻塞的,这样就不会导致生产者进程阻塞了。注意:put_nowait()队列满的时候会抛异常

from multiprocessing import Process, Queue
import time

def producer(q_production):
    num = 1
    while True:
        print("q_production")
        try:
        	# 非阻塞将数据放入队列
        	# 注意:队列满时会抛异常
            q_production.put_nowait(num)
        except:
            pass

        num = num + 1

def consumer(q_consume):
    while True:
        try:
        	# 非阻塞获取队列中的数据
            num = q_consume.get_nowait()
        except:
            num = 0
            pass

        print("q_consume: %d" % num)
        time.sleep(1)

if __name__ == "__main__":
    q = Queue(10)

    test1 = Process(target = producer, args = (q, ))
    test1.start()

    test2 = Process(target = consumer, args = (q, ))
    test2.start()

在这里插入图片描述
另外,这样虽然解决了生产者进程阻塞的问题,但是项目中需要消费者进程获取到的数据是实时的,也就是最新的,Queue无法解决这个问题

方法二
改用共享内存的进程间通信方式:
开辟一个数据大小的共享内存生产者进程不停的去更新这个数据消费者进程每次去读取这个数据得到的都是最新的值

from multiprocessing import Process, Value
import time

def producer(memWrite):
    num = 1
    while True:
        print("memWrite!")
        # 不停的更新共享内存中的值
        memWrite.value = num
        num = num + 1

def consumer(memRead):
    while True:
    	# 读取共享内存中的内容
        print("memRead: %d" % memRead.value)
        time.sleep(1)

if __name__ == "__main__":
	# 申请一块共享内存,大小为2个字节,初始值为0
    shareMem = Value('i', 0)

    test1 = Process(target = producer, args = (shareMem, ))
    test1.start()

    test2 = Process(target = consumer, args = (shareMem, ))
    test2.start()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值