在异步循环中调用os.fork时,设计行为是什么?

问题描述

asyncio是否可以与os.fork()一起使用?

代码段1:

import asyncio
import os

import aiohttp


async def main():
    url = "https://google.com"
    pid = os.fork()
    if pid == 0:
        # child process
        print("in child process")
        await fetch(url)
        print("in child process done")
    else:
        print("in parent process")
        await asyncio.sleep(20)
        print("in parent process done")


async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

if __name__ == "__main__":
    asyncio.run(main())

上面的代码可以正常工作。

代码段2:

import asyncio
import os

import aiohttp


async def main():
    url = "https://google.com"
    pid = os.fork()
    if pid == 0:
        # child process
        print("in child process")
        await asyncio.sleep(10)                  # different with code snippet 1
        # await fetch(url)
        print("in child process done")
    else:
        print("in parent process")
        await asyncio.sleep(20)
        print("in parent process done")


async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

if __name__ == "__main__":
    asyncio.run(main())

上面的代码将引发以下异常:

Traceback (most recent call last):
  File "fork_sleep.py",line 28,in <module>
    asyncio.run(main())
  File "/usr/lib/python3.8/asyncio/runners.py",line 43,in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.8/asyncio/base_events.py",line 616,in run_until_complete
    return future.result()
  File "fork_sleep.py",line 13,in main
    await asyncio.sleep(10)                  # different with code snippet 1
  File "/usr/lib/python3.8/asyncio/tasks.py",line 637,in sleep
    loop = events.get_running_loop()
RuntimeError: no running event loop

“没有运行事件循环”异常的原因是函数get_running_loop比较os.getpid()和保存在循环中的pid。如果它们不同,则会引发上面的异常。

请从cpython源代码中参考以下代码

def get_running_loop():
    """Return the running event loop.  Raise a RuntimeError if there is none.

    This function is thread-specific.
    """
    # NOTE: this function is implemented in C (see _asynciomodule.c)
    loop = _get_running_loop()
    if loop is None:
        raise RuntimeError('no running event loop')
    return loop


def _get_running_loop():
    """Return the running event loop or None.

    This is a low-level function intended to be used by event loops.
    This function is thread-specific.
    """
    # NOTE: this function is implemented in C (see _asynciomodule.c)
    running_loop,pid = _running_loop.loop_pid
    if running_loop is not None and pid == os.getpid():
        return running_loop

因此,如果您不触摸get_running_loop函数,则asyncio事件循环在子进程中似乎可以正常工作。 我的问题是,设计行为是什么?为什么作者检查函数_get_running_loop中的pid?如果在子进程中遇到“无运行事件循环”,那该怎么办?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)