使用anyio替代asyncio

本文介绍了如何将基于asyncio的代码转换为使用anyio库,包括`gather`、`run_until_complete`、`wait_for`和`create_task`等关键功能的用法。通过示例展示了anyio在任务管理、超时控制和错误处理上的实现,并提供了asyncio到anyio的平滑迁移指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Why anyio? 

https://github.com/encode/httpcore/issues/344

https://github.com/encode/httpcore/pull/169

https://github.com/encode/httpcore/pull/420

-----------------------

Updated at 2024-08-22

  这些函数都可以直接从asynctor获取了: pip install asynctor

from asynctor.aio import gather, run_async, wait_for, start_tasks

-----------------------

1. gather

Example:

import anyio


async def gather(*coros):
    results = [None] * len(coros)

    async def runner(coro, i):
        results[i] = await coro

    async with anyio.create_task_group() as tg:
        for i, coro in enumerate(coros):
            tg.start_soon(runner, coro, i)
    return results


async def foo(i):
    print(i)


async def main():
    await gather(*[foo(i) for i in range(5)])


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

2. run_until_complete

asyncio:

import asyncio
from typing import Coroutine
from tortoise import Toirtoise

def run_async(coro: Coroutine) -> None:
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(coro)
    finally:
        loop.run_until_complete(Tortoise.close_connections())

--> anyio:

import anyio
from typing import Coroutine
from tortoise import Toirtoise


def run_async(coro: Coroutine) -> None:
    async def runner():
        try:
            await coro
        finally:
            await Tortoise.close_connections()
    
    anyio.run(runner)
    

3. wait_for

asyncio

import asyncio

try:
    await asyncio.wait_for(do_sth(), 10)
except asyncio.TimeoutError:
    pass

anyio

Cancellation and timeouts — AnyIO 4.0.0 documentation

from typing import Any, Coroutine, Union

import anyio


async def wait_for(coro: Coroutine, timeout: Union[int, float]) -> Any:
    with anyio.fail_after(timeout):
        return await coro


try:
    await wait_for(do_sth, 10)
except TimeoutError:
    pass

4. create_task

asyncio

import asyncio


class Runner:
    def __init__(self):
        self.value = 0
    async def run_main(self):
        while True:
            await asyncio.sleep(0.1)
            self.value += 1

runner = Runner()

@app.on_event('startup')
async def startup():
    asyncio.create_task(runner.run_main())


@app.get('/')
def root():
    return runner.value

anyio


async with: https://peps.python.org/pep-0492/#new-syntax

import anyio
from fastapi import FastAPI

app = FastAPI()


class Runner:
    def __init__(self):
        self.value = 0

    async def run_main(self):
        while True:
            await anyio.sleep(0.1)
            self.value += 1


runner = Runner()


def register(app):
    tg = anyio.create_task_group()
    scope = anyio.CancelScope(shield=True)

    @app.on_event("startup")
    async def startup():
        await tg.__aenter__()
        scope.__enter__()
        tg.start_soon(runner.run_main)

    @app.on_event("shutdown")
    async def shutdown():
        tg.cancel_scope.cancel()
        scope.__exit__(None, None, None)
        await tg.__aexit__(None, None, None)


register(app)


@app.get("/")
def root():
    return runner.value

或anyio+lifespan

from contextlib import asynccontextmanager

import anyio
from fastapi import FastAPI


class Runner:
    def __init__(self):
        self.value = 0

    async def run_main(self):
        while True:
            await anyio.sleep(0.1)
            self.value += 1


runner = Runner()


@asynccontextmanager
async def lifespan(app: FastAPI):
    async with anyio.create_task_group() as tg:
        with anyio.CancelScope(shield=True):
            tg.start_soon(runner.run_main)
            yield
            tg.cancel_scope.cancel()


app = FastAPI(lifespan=lifespan)


@app.get("/")
def root():
    return runner.value

https://anyio.readthedocs.io/en/stable/cancellation.html#shielding

封装成asyncio风格的:

from contextlib import asynccontextmanager
from typing import Callable, Coroutine

import anyio
from fastapi import FastAPI


def be_afunc(coro: Coroutine) -> Callable:
    async def do_await():
        return await coro

    return do_await


@asynccontextmanager
async def create_task(coro: Coroutine, *more: Coroutine):
    async with anyio.create_task_group() as tg:
        with anyio.CancelScope(shield=True):
            tg.start_soon(be_afunc(coro))
            for c in more:
                tg.start_soon(be_afunc(c))
            yield
            tg.cancel_scope.cancel()


class Runner:
    def __init__(self) -> None:
        self.value = 0

    async def run_main(self) -> None:
        while True:
            await anyio.sleep(0.1)
            self.value += 1


runner = Runner()


@asynccontextmanager
async def lifespan(app: FastAPI):
    async with create_task(runner.run_main()):
        yield


app = FastAPI(lifespan=lifespan)


@app.get("/")
def root():
    return runner.value

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值