前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python多进程假死

python多进程假死

作者头像
lovelife110
发布2021-01-14 14:43:02
2.7K0
发布2021-01-14 14:43:02
举报
文章被收录于专栏:爱生活爱编程爱生活爱编程

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

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

原理分析

模拟子进程阻塞:

代码语言:javascript
复制
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")

原因分析:

代码语言:javascript
复制
#
# Queue type using a pipe, buffer and thread
#

class Queue(object):

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

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

代码语言:javascript
复制
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")

正确的写法

代码语言:javascript
复制
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前面,不然主进程等待子进程结束,而子进程等待队列数据取走,造成死锁

代码语言:javascript
复制
    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 语言里实现多线程

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-08-23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 原理分析
  • Python多线程补充
    • python多线程应用
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档