python - 在异步循环中调用 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?如果您在子进程中遇到“没有运行的事件循环”,解决方案是什么。
解决方案
推荐阅读
- listview - Xamarin 自定义列表视图
- javascript - 如何使用 node.js 以角度下载图像?
- postgresql - Heroku 未使用 CLI 连接到 Heroku Postgres
- kotlin - 在 Kotlin 应用程序中验证使用 javascript 签名的签名
- amazon-web-services - 根据条件块创建一个资源,该资源从cloudformation中的自定义资源中获取输出?
- yaml - 使用 YAML-changelog 时,带有 Maven 的 Liquibase 错过了课程
- f# - 使用来自另一个模块的 XML-Typeprovider
- php - php mysql为同一个表id插入数组键值
- android - 使用 elvis 运算符回退 gradle 中的未知属性
- spring - 如何在 logback.xml 中使用 Spring 应用程序属性