• python(一):multiprocessing——死锁


    前言
    近年来,使用python的人越来越多,这得益于其清晰的语法、低廉的入门代价等因素。尽管python受到的关注日益增多,但python并非完美,例如被人诟病最多的GIL(值得注意的是,GIL并非python特性,它是在实现Python解析器(CPython)时所引入的一个概念,而CPython是大部分环境下默认的Python执行环境),全称Global Interpreter Lock。从官方定义来看,GIL无疑就是一把全局排他锁,会严重影响python多线程的效率,甚至几乎等于Python是个单线程程序。

    为了满足开发者的需求,python社区推出了multiprocessing。顾名思义,multiprocessing使用了多进程而不是多线程,每个进程有自己的独立的GIL,因此也不会出现进程之间的GIL争抢。当然multiprocessing也并非完美,例如增加了数据通讯的难度等方面。讲了这么多背景,下面分享一下使用multiprocessing踩过的坑。由于这篇博客偏向实际工程,主要分享应用经验,相关基础知识可以查阅Python Documentation。

    系统
    >>> import sys
    >>> print(sys.version)
    3.6.0 |Anaconda 4.3.1 (64-bit)| (default, Dec 23 2016, 12:22:00) [GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]
    1
    2
    3
    死锁
    百度百科对死锁的定义

    死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程1。

    从定义可知,永远互相等待是死锁的一个重要特征。在multiprocessing中,你稍不留神,也会犯这种错误,例如:

    from multiprocessing import Process, Queue

    def f(q):
    q.put('X' * 1000000)

    if __name__ == '__main__':
    queue = Queue()
    p = Process(target=f, args=(queue,))
    p.start()
    p.join() # this deadlocks
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    结果是死锁。当一个进程被join时,Python会检查被放入Queue中的数据是否已经全部删除(例如Queue.get),若没有删除,则进程会一直处于等待状态。发现这种情况时,一方面感叹“你让我找的好苦啊”,另一方面思考python的开发者怎么会对这种情况坐视不理呢?是否做了某些尝试?例如若Queue小于某个阈值,进程join会将其视为空Queue。基于这种猜想,做了以下实验

    from multiprocessing import Process, Queue
    import time

    def f(q):
    num = 10000
    q.put('X' * num)
    print("Finish put....")

    if __name__ == '__main__':
    queue = Queue()
    p = Process(target=f, args=(queue,))
    p.start()
    print("Start to sleep...")
    time.sleep(2)
    print("Wake up....")
    p.join()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    结果是程序正常结束,一定程度上验证了我的猜想。为了进一步确定猜想的正确性,我又做了num=1000、num=100和num=1的实验,结果均是程序正常结束,证明进程join时的确会判断Queue的大小,从而避免死锁。尽管这种策略有一定效果,但并不能根治死锁,所以进程join时一定要保证Queue中数据已经被全部取走。

    除了上述的情况外,进程join自身、终止带锁的进程等情况也会导致死锁,以后会慢慢分享给大家。

    结语
    尽管multiprocessing对死锁有一定的容错能力,但并不完善,优化代码才是正道。
    ---------------------
    作者:cptu
    来源:CSDN
    原文:https://blog.csdn.net/AckClinkz/article/details/78409301
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    BZOJ2565:最长双回文串
    BZOJ2342:[SHOI2011]双倍回文
    Redis数据库基础操作
    Celery异步任务框架
    Django框架之缓存数据库
    drf 分页器组件
    drf jwt认证组件
    drf三大认证组件
    Django框架之RBAC+ContentType
    Django框架之admin管理后台
  • 原文地址:https://www.cnblogs.com/ExMan/p/10142477.html
Copyright © 2020-2023  润新知