空的python进程在join [sys.stderr.flush()]上挂起

Python大师我需要你的帮助.我遇到了很奇怪的行为:

空python进程挂起加入.看起来它会分配一些锁定的资源.

ENV:

> Python版本:3.5.3
>操作系统:Ubuntu 16.04.2 LTS
>内核:4.4.0-75-通用

问题描述:

1)我有一个带有线程的记录器来处理该线程的后台和队列中的消息. Logger source code(稍微简化一点).

2)我有一个简单的脚本使用我的记录器(只是代码来显示我的问题):

import os
from multiprocessing import Process
from my_logging import get_logger


def func():
    pass


if __name__ == '__main__':

    logger = get_logger(__name__)
    logger.start()
    for _ in range(2):
        logger.info('message')

    proc = Process(target=func)
    proc.start()
    proc.join(timeout=3)
    print('TEST PROCESS JOINED: is_alive={0}'.format(proc.is_alive()))

    logger.stop()
    print('EXIT')

有时这个测试脚本会挂起.脚本在加入进程“proc”时挂起(当脚本完成执行时).测试过程“proc”保持活力.

要重现此问题,您可以在循环中运行脚本:

$for i in {1..100} ; do /opt/python3.5.3/bin/python3.5 test.py ; done

调查:

Strace展示如下:

strace: Process 25273 attached
futex(0x2275550, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL, ffffffff

我想出了流程挂起的地方.它在多处理模块中挂起,文件process.py,第269行(python3.5.3),在刷新STDERR时:

...
267    util.info('process exiting with exitcode %d' % exitcode)
268    sys.stdout.flush()
269    sys.stderr.flush()
...

如果第269行注释,则脚本始终成功完成.

我的想法:

默认情况下,logging.StreamHandler使用sys.stderr作为流.

如果在记录器将数据刷新到STDERR时分叉了进程,则进程上下文会获得一些锁定的资源,并在刷新STDERR时进一步挂起.

一些解决问题的解决方法:

>使用python2.7.我无法用python2.7重现它.也许时间阻止我重现这个问题.
>使用进程处理记录器中的消息而不是线程.

你对这种行为有什么想法吗?问题出在哪儿?难道我做错了什么?

最佳答案 看起来这种行为与此问题有关:
http://bugs.python.org/issue6721

点赞