MST

星途 面试题库

面试题:Go的context API函数在复杂业务场景下的运用

有一个多层嵌套调用的业务逻辑,最外层函数发起一个请求,然后会调用多个子函数进行不同的数据获取和处理操作,每个子函数可能又会启动新的协程。现在需要在最外层设置一个全局的取消机制,当用户在一定时间内未操作时取消所有正在执行的任务。请使用context API函数设计一个代码框架来实现这个功能,并且说明如何将context传递到各个子函数及协程中。
21.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
import asyncio
import signal
import contextlib


async def sub_coroutine(ctx, task_name):
    try:
        while not ctx.canceled():
            await asyncio.sleep(1)
            print(f"{task_name} is running...")
    except asyncio.CancelledError:
        print(f"{task_name} was cancelled.")


async def sub_function(ctx, task_name):
    await asyncio.gather(sub_coroutine(ctx, task_name))


async def main():
    ctx, cancel = contextlib.asynccontextmanager(asyncio.get_running_loop().create_task)(asyncio.timeout(5))
    try:
        await asyncio.gather(
            sub_function(ctx, "Task1"),
            sub_function(ctx, "Task2")
        )
    except asyncio.TimeoutError:
        print("Timeout, cancelling tasks...")
        cancel()
    finally:
        await ctx.aclose()


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.add_signal_handler(signal.SIGINT, loop.stop)
    try:
        loop.run_until_complete(main())
    finally:
        loop.close()

如何传递context

  1. 函数参数传递:在main函数中创建context对象ctx后,通过函数参数将ctx传递给sub_function
  2. 协程参数传递sub_function函数接收ctx后,又将其作为参数传递给sub_coroutine协程。这样在每个子函数和协程中都能获取到context对象,当context被取消时,各个子任务能够捕获asyncio.CancelledError异常从而正确处理取消操作。