【发布时间】:2017-10-19 13:32:45
【问题描述】:
Python 大师我需要你的帮助。我遇到了非常奇怪的行为: 空 python 进程在加入时挂起。看起来它分叉了一些锁定的资源。
环境:
- 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 重现它。也许时间安排使我无法重现该问题。
- 使用进程在记录器而不是线程中处理消息。
你对这种行为有什么想法吗?问题出在哪里?我做错了吗?
【问题讨论】:
-
我@dmitry-moroz,我面临同样的问题(python 3.5)。问题解决了吗?
标签: python multithreading logging multiprocessing fork