您的位置:首页 > 编程语言 > Python开发

代码干货 | 一个Reentrant Error引发的对Python信号机制的探索和思考

2017-09-18 13:56 579 查看
本文来源于阿里云-云栖社区,原文点击这里

前几天工作时遇到了一个匪夷所思的问题。经过几次尝试后问题得以解决,但问题产生的原因却仍令人费解。查找 SO 无果,我决定翻看
Python 的源码。断断续续地研究了几天,终于恍然大悟。撰此文以记。

本文环境:
Ubuntu 16.04 (64 bit)
Python 3.6.2

使用的 C 源码可以从 Python 官网 获取。

起因

工作时用到了 celery 作为异步任务队列,为方便调试,我写了一个脚本用以启动/关闭 celery 主进程。代码简化后如下:

import sys 
 
import subprocess 
 
# ... 
 
celery_process = subprocess.Popen( 
 
    ['celery', '-A', 'XXX', 'worker'], 
 
    stdout=subprocess.PIPE, 
 
    stderr=sys.stderr 
 

 
try: 
 
    # Start and wait for server process 
 
except KeyboardInterrupt: 
 
    # Ctrl + C pressed 
 
    celery_process.terminate() 
 
    celery_process.wait()  

代码启动了 celery worker,并尝试在捕获到
KeyboardInterrupt 异常时将其热关闭。

初看上去没什么问题。然而实际测试时却发生了十分诡异的事情:按下 Ctrl+C 后,程序 偶尔 会抛出这样的异常:RuntimeError: reentrant call inside <_io.BufferedWriter name='<stdout>’>。诡异之处有两点:

异常发生的时机有随机性

异常的 traceback 指向 celery 包,也就是说这是在 celery 主进程内部发生的异常

这个结果大大出乎了我的意料。随机性异常是众多最难缠的问题之一,因为这常常意味着并发问题,涉及底层知识,病灶隐蔽,调试难度大,同时没有有效的手段判断问题是否彻底解决(可能只是降低了频率)。

 展开全文
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息