踩坑 多进程、多线程、队列

目标:多个生产者(放入队列数据), 和一个监督者(输入字符,可输出指定信息, 如队列长度,生产总个数等等)

先看看最初的代码(单生产者):

import time
from multiprocessing import Process, Queue

cache = Queue(maxsize=100)


# 生产区
def Product():
    t1 = 1
    while True:
        time.sleep(0.5)
        cache.put(f'苹果{t1}')
        t1 += 1


# 启动生产进程
P1 = Process(target=Product)
P1.daemon = True
P1.start()

# 监督区
print('(监督区) 请输入相关操作指令:')
while True:
    try:
        ComTO = int(input())
        if ComTO == 1:
            print(P1.is_alive())
            print(f'当前生产总个数:{cache.qsize()}')
    except Exception as e:
        print(f'发生错误:{e}')
第一坑:进程一定要放到main中:

代码测试结果:
在这里插入图片描述

解决方式:进程的使用放入main中
...
if __name__ == '__main__':
    # 启动生产线程
    P1 = Process(target=Product)
    P1.daemon = True
    P1.start()

    # 监督区
    print('(监督区) 请输入相关操作指令:')
    while True:
        try:
            ComTO = int(input())
            if ComTO == 1:
                print(P1.is_alive())
                print(f'当前缓存个数:{cache.qsize()}')
        except Exception as e:
            print(f'发生错误:{e}')

然后就进入了第二坑

第二坑 队列在进程中,一定要用传参的方式调用队列(直接使用全局变量不行,不知道底层原因。。。)

以上最终代码测试结果(输入时都是有延迟的,没有狂按输入):
在这里插入图片描述

分析和解决方式

可以看到进程P1是正在运行中的,按道理应该队列中是有值了,但是实际输出时,队列一直为空。很明显队列中没有数据,后来经过测试,发现队列需要传进去,直接使用全局变量是不行的。

# 生产区
def Product(Cache):
    print('开始生产')
    t1 = 1
    while True:
        time.sleep(0.5)
        Cache.put(f'苹果{t1}')
        t1 += 1
# 启动生产线程
P1 = Process(target=Product, args=(cache, ))
P1.daemon = True
P1.start()

测试结果:
在这里插入图片描述

细心点的肯定都发现了另外一个小问题,刚开始运行时,都是在我输入第一个值以后才开始生产,但理论上应该是互不影响。

(自己理解的,不知是不是真的原因,修改后确实可用)
这里是因为进程还未启动完成,就遇到了input,这个时候就要等待input完成后再接下来输出,然后在第二个input之前就启动了进程,这个时候加个小延迟就好了。

...
P1 = Process(target=Product, args=(cache, ))
P1.daemon = True
P1.start()
time.sleep(0.1)
# 监督区
print('(监督区) 请输入相关操作指令:')
...

在这里插入图片描述
然后在进程中添加几个线程,分别负责生产。

# 生产区
def Product(Cache):
    print('开始生产')

    def Apple(Cache1):
        t2 = 1
        while True:
            time.sleep(0.5)
            Cache1.put(f'苹果{t2}')
            t2 += 1

    def Banana(Cache1):
        t2 = 1
        while True:
            time.sleep(0.5)
            Cache1.put(f'香蕉{t2}')
            t2 += 1

    T1 = Thread(target=Apple, args=(Cache,))
    T2 = Thread(target=Banana, args=(Cache,))
    T1.daemon = True
    T2.daemon = True
    T1.start()
    T2.start()
第三坑 多进程中有线程(守护线程)时,一定要让进程保持存活,不然线程也会挂掉

以上最终代码测试结果:
在这里插入图片描述

分析和解决方式

可以看到进程在第一次输入时,就已经挂掉了。
原因是因为进程中有且只有线程,线程一启用,进程中就已经执行完了,所以进程结束,同样该进程的守护线程也挂掉了。

这个解决方法就比较多了,要么加个延迟(time.sleep()), 要么去掉一个线程直接放到进程中。这两个方法都有一定缺点,最好还是加个循环判断:

def Product(Cache):
	...
    T1.start()
    T2.start()
    # 如果有一个线程存活就等待一秒
    while T1.is_alive() or T2.is_alive():
        time.sleep(1)
    return
...

最终代码(原有基础上增加一个全输出功能):

import time
from multiprocessing import Process, Queue
from threading import Thread

cache = Queue(maxsize=100)


# 生产区
def Product(Cache):
    print('开始生产')

    def Apple(Cache1):
        t2 = 1
        while True:
            time.sleep(0.5)
            Cache1.put(f'苹果{t2}')
            t2 += 1

    def Banana(Cache1):
        t2 = 1
        while True:
            time.sleep(0.5)
            Cache1.put(f'香蕉{t2}')
            t2 += 1

    T1 = Thread(target=Apple, args=(Cache,))
    T2 = Thread(target=Banana, args=(Cache,))
    T1.daemon = True
    T2.daemon = True
    T1.start()
    T2.start()
    # 如果有一个线程存活就等待一秒
    while T1.is_alive() or T2.is_alive():
        time.sleep(1)
    return


def Check():
    print('(监督区) 请输入相关操作指令:')
    while True:
        try:
            ComTO = int(input())
            if ComTO == 1:
                print(P1.is_alive())
                print(f'当前生产总个数:{cache.qsize()}')
            elif ComTO == 2:
                temp = []
                while cache.qsize() != 0:
                    temp.append(cache.get())
                print(f'输出全部:{temp}')
        except Exception as e:
            print(f'发生错误:{e}')


if __name__ == '__main__':
    # 启动生产
    P1 = Process(target=Product, args=(cache,))
    P1.daemon = True
    P1.start()
    time.sleep(0.1)
    # 启动监督
    Check()

结果:
在这里插入图片描述
完美!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值