簡體   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