繁体   English   中英

当脚本在多处理工作程序中运行asyncio eventloop时,通过子进程运行脚本会挂起

[英]Running a script through subprocess hangs when script runs an asyncio eventloop inside multiprocessing workers

在Windows上运行Python 3.7.3,

我有一种情况, asyncio事件循环永远不会从多处理产生的进程中产生。 我无法显示所有代码,但它是这样的:

  1. 我使用multiprocessing来加速使用第三方API的查询。
  2. 此API thirdparty.api支持服务器 - 客户端体系结构,并在内部使用asyncio事件循环。 它在一个单独的线程中运行一个事件循环; 在该线程中,它调用event_loop.run_forever()并仅在KeyboardInterrupt上调用。
  3. 使用多处理运行工作程序脚本,API始终返回,无论成功还是失败。 以前我点击了Py3.7.2回归,在Windows上,venv Python可执行文件的工作方式很糟糕https://bugs.python.org/issue35797 但现在已在Py3.7.3中修复,我的问题仍然存在。
  4. 使用subprocess进程从另一个Py27脚本运行此脚本。 在我的多处理工作进程中,如果查询失败,则调用永远不会返回,并且它无法自然地突破工作进程,即使是通用异常处理程序也不会捕获任何内容并且会卡住。

我的调用者脚本的代码片段:

#!/usr/bin/env python2

def main()
    try:
        cmd = ['C:\\Python\\Python37\\pythonw.exe', 'worker.py']
        print(' '.join(cmd))
        proc = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        out, err = proc.communicate()
    except subprocess.CalledProcessError as err:
        print(err)
    except Exception:
        traceback.print_exc()
    else:
        print('try popen finished with else.')
    print('stdout: {}'.format(out))
    print('stderr: {}'.format(err))


if __name__ == '__main__':
    main()

我的worker worker.py函数的伪代码片段如下所示:

#!/usr/bin/env python3

args = [
   ...
]


def worker(*mpargs):
    with thirdparty.api() as myclient:
        try:
            myclient.query(*args)
        except Exception:
            traceback.print_exc()


def exception_worker(*mpargs)
    raise RuntimeError('Making trouble!')


def main():
    logging.info('STARTED!')
    with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
        results = pool.map(worker, args)
        # results = pool.map(exception_worker, args)
        pool.close()
        pool.join()
    logging.info('ALL DONE!')


if __name__ == '__main__':
    main()

thirdparty.api在其构造函数中启动事件循环:

self.loop = asyncio.get_event_loop()
if self.loop.is_closed():
    self.loop = asyncio.new_event_loop()
    asyncio.set_event_loop(self.loop)

然后在其单独的线程中:

try:
    self._loop.run_forever()
except KeyboardInterrupt:
    pass
self.loop.close()

我已经尝试了另一个工作者exception_worker ,它只抛出异常,并且这个返回没有问题。

我该怎么解决这个问题?

在详细说明问题后,我终于在这篇文章中找到了解决方案: 为什么我在Windows上使用async和await获取NotImplementedError?

thirdparty.api需要关注这个细节,在修复之后,我的问题就消失了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM