python多进程假死

结论:python多进程间用Queue通信时,如果子进程操作Queue满了或者内容比较大的情况下,该子进程会阻塞等待取走Queue内容(如果Queue数据量比较少,不会等待),如果调用join,主进程将处于等待,等待子进程结束,造成死锁

解决方式:在调用join前,及时把Queue的数据取出,而且Queue.get需要在join前

原理分析

模拟子进程阻塞:

from multiprocessing import Process, Queue


def fun(q):
    num = 1000000000
    q.put('=' * num)
    print("done put")


if __name__ == '__main__':
    queue = Queue()
    p = Process(target=fun, args=(queue,))
    p.start()
    p.join()
    print("done")

原因分析:

#
# Queue type using a pipe, buffer and thread
#

class Queue(object):

multiprocessing.Queue底层是基于Pipe构建,操作系统管道不是无限长,因此子进程在执行put()期间,处于阻塞,直到某些其他进程使用get()从队列中取走数据。上例中,主进程等待子进程,打印不了done

 

而当队列put数据比较少时,是没有问题的,先打印done put,再打印done,但这样写法是有隐患,当put数据比较多时,就会阻塞

from multiprocessing import Process, Queue


def fun(q):
    num = 1
    q.put('=' * num)
    print("done put")


if __name__ == '__main__':
    queue = Queue()
    p = Process(target=fun, args=(queue,))
    p.start()
    p.join()
    print("done")

正确的写法

from multiprocessing import Process, Queue


def fun(q):
    num = 1000000000
    q.put('=' * num)
    print("done put")


if __name__ == '__main__':
    queue = Queue()
    p = Process(target=fun, args=(queue,))
    p.start()
    queue.get()
    p.join()
    print("done")

在join前面调用queue.get

 

注意!!!以下这样写法也是不对的,join要在queue.get前面,不然主进程等待子进程结束,而子进程等待队列数据取走,造成死锁

    p = Process(target=fun, args=(queue,))
    p.start()
    p.join()
    queue.get()

 

Python多线程补充

Python 是一门解释型语言,它的执行是由解释器来控制的。

GIL,全称是 Global Interpreter Lock ,全局解释锁 ,专门给解释器用

一般情况下在用户态下是无法做到线程级别的时间片轮转

但是 python 能做到!python 里,解释器可以记录每一个线程执行了多长时间——时间一到,就能够切换到另一条线程。

GIL 就是拿来给线程加锁的,当一个线程将要执行时,解释器会把 GIL 锁给这个线程,其他线程因为没有锁,是无法运行的。等到持有锁线程阻塞或者运行 100 个字节码,解释器就会把锁交给其他线程

但是这个 GIL 锁是全局(Global)的,也就导致即使是多核情况下,一次也只有一个线程能运行,从整体上看,整个程序是串行的

python多线程应用

拿爬虫程序来说吧,单个爬虫总会花时间在下载网页上,很多 CPU 时间就浪费掉了,提供 sleep 机制后,这些爬虫可以在等待下载时释放 GIL 锁,把机会让给其他爬虫,这样整体运行速度能够得到大幅提升

也就是说 Python 的多线程适合 I/O 密集型的程序,但是对计算密集型程序就不那么友好了

对于计算密集型程序用多进程或者让 python 调用 C 语言的代码,在 C 语言里实现多线程

  • 42
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lovelife110

你的鼓励是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值