You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于asyncio中_run_until_complete_cb触发时机与VSCode调试的问询

Let's break down your questions step by step, since asyncio's internal flow can feel opaque at first glance.

1. When does the Future complete, triggering _run_until_complete_cb?

First, let's recap the core flow of your code:

  • asyncio.run(main()) creates an event loop under the hood, then calls loop.run_until_complete(main()) to execute your coroutine.
  • run_until_complete wraps your main coroutine into a Task (a subclass of Future), then registers _run_until_complete_cb as a done callback via add_done_callback.

The critical moment when the Future (your main Task) transitions from _PENDING to completed happens when your main coroutine finishes executing:

  • After your main coroutine runs print("Wake up!"), it reaches the end of the function (an implicit return None).
  • The Task instance wrapping your coroutine handles this completion in its internal step method. When the coroutine iterator is exhausted (no more yields), the Task calls self.set_result(None) to mark itself as finished.
  • set_result changes the Task's _state from _PENDING to _FINISHED, then iterates over all callbacks stored in _callbacks (including _run_until_complete_cb). It schedules each callback with loop.call_soon to run in the next iteration of the event loop.

Once _run_until_complete_cb executes, it sets the event loop's _stopping flag to True, which tells the loop to exit after processing any remaining pending callbacks.

2. Debugging Future/Task methods in VS Code

VS Code's debugger skips over standard library code (like asyncio's Future/Task methods) by default, which is why you're not seeing those internal calls. Here are practical fixes to trace into these methods:

  • Disable "Just My Code":
    Open your .vscode/launch.json configuration, and add or set "justMyCode": false. This tells the debugger to step into non-user code (like asyncio's source) instead of skipping it. A sample launch config might look like this:

    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "Python: Current File",
                "type": "python",
                "request": "launch",
                "program": "${file}",
                "justMyCode": false
            }
        ]
    }
    
  • Enable asyncio debug mode:
    Change your call to asyncio.run(main(), debug=True). This enables asyncio's built-in debugging infrastructure, which adds extra checks, makes internal state transitions more visible, and helps the debugger track async flows more reliably.

  • Set targeted breakpoints:
    If you want to break exactly when the Task completes, you can set a breakpoint directly in asyncio's set_result method (look for the Future class in your Python installation's asyncio/futures.py file), or in the step method of the Task class (asyncio/tasks.py). This lets you observe exactly when the state changes and callbacks are triggered.

  • Inspect Task state in the debug console:
    While debugging, you can use the debug console to check the state of your Task. For example, temporarily modify your code to capture the Task instance:

    if __name__ == "__main__":
        loop = asyncio.get_event_loop()
        task = loop.create_task(main())
        loop.run_until_complete(task)
    

    Then, in the debug console, run task._state or task.done() to check if it's completed at any point in the flow.

Hope this clears up the confusion around asyncio's cleanup flow and helps you debug more effectively!

内容的提问来源于stack exchange,提问作者BrainVader

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:06:15