进程之joinableQueue

joinableQueue是Python中一种特殊的队列,它提供了join()函数,用于阻塞直到队列中的所有数据被处理完毕。get()操作仅取出数据,而task_done()通知队列数据已被处理。调用task_done()的次数必须大于等于队列数据个数,join()才会结束阻塞。在不确定数据量的场景,如爬虫抓取未知数量页面时,joinableQueue能让主进程获知数据处理状态,从而结束子进程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

joinableQueue

可翻译:为可join的队列

该队列相比普通的Queue的区别在于该对列额外增加的了join函数

 

join函数的作用:

该函数为阻塞函数,会阻塞直到等待队列中所有数据都被处理完毕。

q = JoinableQueue()
q.put(1) 
q.get()
q.join() #阻塞 等待队列中所有数据都被处理完毕
print("over")

执行以上函数,将导致进程无法结束,注释掉join调用就正常,发现join的确有阻塞的效果,

但是队列中一共就一个数据,明明已经调用get取出了,为什么join依然阻塞呢?

这是因为get仅仅是取出数据,而join是等待数据处理完毕,也就是说:

取出数据还不算完,你处理完以后必须告知队列处理完毕,通过task_done

q = JoinableQueue()
q.put(1) 
​
q.get()
q.task_done() # 数据处理完毕
​
q.join() #阻塞 等待队列中所有数据都被处理完毕
print("over")
#输出:
#   over

需要注意的时,task_done的调用次数必大于等于队列中的数据个数,join才能正常结束阻塞

q = JoinableQueue()
q.put(1) 
q.put(1) 
​
q.get()
q.task_done() # 数据处理完毕
​
​
q.join() #阻塞 等待队列中所有数据都被处理完毕
print("over")
#输出:
#   over

总结:

主进程可以明确知道队列中的数据何时被处理完毕

 

守护进程与joinablequeue的应用

回顾之前的生产者消费者模型中,生产者与消费者都明确要处理的数据数量,但是实际开发中很多情况是无法提前明确的,例如:要爬去一个网站上的所有页面,页面数量数不固定的

from multiprocessing import Process,JoinableQueue,Queue
import  time,random
def producter(name,q):
    for i in range(5):
        time.sleep(random.randint(1,2))
        print("\033[46m%s生产了 热狗%s\033[0m" % (name,i))
        q.put("%s的 热狗%s" % (name,i))
​
​
def customer(name,q):
    while True:
        time.sleep(random.randint(1, 2))
        hot_dog = q.get()
        print("\033[47m%s 吃掉了 %s \033[0m" % (name,hot_dog))
​
if __name__ == '__main__':
​
    q = Queue()
​
    p1 = Process(target=producter,args=("北京?店",q))
    p2 = Process(target=producter,args=("上海?店",q))
    p3 = Process(target=producter, args=("深圳?店", q))
    p1.start()
    p2.start()
    p3.start()
​
    c1 = Process(target=customer,args=("王思聪",q))
    c1.start()

上述代码无法正常运行结束,是因为消费者进程中不清楚处理是否处理完成,所以一直在循环等待数据。

此时我们就可以使用joinablequeue队列来让主进程获取生成者进程是否生成完毕的信号从而结束子进程

from multiprocessing import Process,JoinableQueue,Queue
​
​
​
​
# q = JoinableQueue()
#
# q.put(1)
# q.put(1)
#
# q.get()
# q.task_done()
#
#
# q.join() #阻塞 等待队列中所有数据都被处理完毕
# print("over")
​
import  time,random
def producter(name,q):
    for i in range(5):
        time.sleep(random.randint(1,3))
        print("\033[46m%s生产了 热狗%s\033[0m" % (name,i))
        q.put("%s的 热狗%s" % (name,i))
​
​
def customer(name,q):
    while True:
        time.sleep(random.randint(1, 2))
        hot_dog = q.get()
        print("\033[47m%s 吃掉了 %s \033[0m" % (name,hot_dog))
        # 一个数据处理完毕
        q.task_done()
​
if __name__ == '__main__':
​
    # q = Queue()
    q = JoinableQueue()
​
    p1 = Process(target=producter,args=("北京?店",q))
    p2 = Process(target=producter,args=("上海?店",q))
    p3 = Process(target=producter, args=("深圳?店", q))
    p1.start()
    p2.start()
    p3.start()
​
    c1 = Process(target=customer,args=("王思聪",q))
    c1.daemon = True # 使子进程跟随主进程结束
    c1.start()
​
    # 等待生产者进程全部生成完毕
    p1.join()
    p2.join()
    p3.join()
​
    # 等待所有数据全部处理完毕
    q.join()
​
    # 终止子进程 也可以开启子进程前将子进程设置为守护进程来结束子进程
    # c1.terminate()

进程池:

进程池与线程池使用方法完全一致,放到线程池一起讲

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值