asyncio.run asyncio.run_coroutine_threadsafe loop.run_until_complete create_task的区别

本文介绍了Pythonasyncio库中四种关键的协程管理方法:asyncio.run用于主入口点的单线程执行,asyncio.run_coroutine_threadsafe适用于多线程环境,loop.run_until_complete在事件循环中阻塞等待,create_task用于并行任务创建。

asyncio.run, asyncio.run_coroutine_threadsafe, loop.run_until_complete, 和 create_task 是 Python asyncio 中用于管理协程的不同方法,它们在协程的执行和管理方式上有一些区别。

  1. asyncio.run:

    • asyncio.run 是 Python 3.7+ 引入的,用于运行一个协程并等待其完成。
    • 它通常用于应用程序的主入口点,以便在应用程序中方便地运行一个协程。
    • 它创建一个新的事件循环,运行协程,等待协程完成,然后关闭事件循环。

    示例:

    import asyncio
    
    async def main():
        await asyncio.sleep(1)
        print("Hello, world!")
    
    asyncio.run(main())
    
  2. asyncio.run_coroutine_threadsafe:

    • asyncio.run_coroutine_threadsafe 是用于在一个线程中安全地运行协程,并且可以从另一个线程提交协程进行执行。
    • 这在多线程环境下是有用的,可以安全地将协程任务提交给事件循环。
    • 它返回一个 concurrent.futures.Future 对象,您可以使用 .result() 方法来等待协程的结果。
    • asyncio.run_coroutine_threadsafe 函数通常在多线程环境中使用,它会将协程提交到指定的事件循环(在本例中是 loop)中运行,并返回一个 concurrent.futures.Future 对象。在代码中,使用 future.result() 获取协程的结果,但可能因为线程同步的问题导致卡死。

      如果你在单线程环境中使用 asyncio,最简单的方式是使用 asyncio.run 来运行协程

    示例:

    import asyncio
    
    async def my_coroutine():
        await asyncio.sleep(1)
        return "Hello, world!"
    
    async def main():
        future = asyncio.create_task(my_coroutine())
        result = await future
        return result
    
    if __name__ == "__main__":
        result = asyncio.run(main())
        print(result)
    
  3. loop.run_until_complete:

    • loop.run_until_complete 是 asyncio 事件循环对象的方法,用于运行一个协程并等待其完成。
    • 这个方法只能在事件循环的上下文中使用。
    • 它会一直阻塞,直到协程执行完成,然后返回协程的结果。

    示例:

    import asyncio
    
    async def my_coroutine():
        await asyncio.sleep(1)
        return "Hello, world!"
    
    loop = asyncio.get_event_loop()
    result = loop.run_until_complete(my_coroutine())
    print(result)
    
  4. create_task:

    • create_task 是 asyncio 事件循环对象的方法,用于将协程封装为一个任务对象并立即返回任务对象。
    • 任务是协程的包装器,它可以在后台并行执行,而不需要等待其完成。
    • 通常用于同时启动多个协程任务。

    示例:

    import asyncio
    
    async def my_coroutine(task_name, seconds):
        await asyncio.sleep(seconds)
        return f"{task_name} completed after {seconds} seconds"
    
    async def main():
        task1 = asyncio.create_task(my_coroutine("Task 1", 2))
        task2 = asyncio.create_task(my_coroutine("Task 2", 1))
    
        # 此处可以做其他事情,不需要等待任务完成
    
        result1 = await task1
        result2 = await task2
    
        print(result1)
        print(result2)
    
    asyncio.run(main())
    

总结:

  • asyncio.run 用于运行一个协程并等待其完成,通常在应用程序的入口点处使用。
  • asyncio.run_coroutine_threadsafe 用于在多线程环境中安全地运行协程,可以从不同的线程中提交协程进行执行。
  • loop.run_until_complete 用于运行一个协程并等待其完成,通常在事件循环的上下文中使用。
  • create_task 用于创建并行执行的任务,通常在需要同时启动多个协程时使用,然后您可以等待这些任务的完成。
<think>我们注意到用户的问题是关于asyncssh库中run_until_complete函数的用法。但是,根据我们已有的知识,run_until_complete并不是asyncssh库中的方法,而是asyncio事件循环的方法。在asyncssh中,我们通常使用asyncio的事件循环来运行异步协程。 用户可能混淆了asyncio和asyncssh的API。因此,我们需要澄清: - `run_until_complete` 是 `asyncio.AbstractEventLoop` 的方法,用于运行一个协程直到完成。 - asyncssh是一个异步SSH库,它的方法都是协程,需要在事件循环中运行。 下面我们将重点解释如何在asyncssh的上下文中使用`run_until_complete`。 引用[1]和引用[2]提到:`loop.run_until_complete`用于运行一个协程直到完成,并且它会阻塞当前线程直到协程执行完毕。引用[3]和引用[4]则说明了它如何将协程包装成future并运行。 因此,在asyncssh中,我们通常这样使用: 示例1:基本连接和命令执行 ```python import asyncio import asyncssh async def run_ssh_command(): async with asyncssh.connect('localhost', username='user', password='pass') as conn: result = await conn.run('ls') print(result.stdout) loop = asyncio.get_event_loop() loop.run_until_complete(run_ssh_command()) ``` 示例2:使用多个连接 ```python async def run_multiple_commands(): commands = ['ls', 'pwd', 'whoami'] async with asyncssh.connect('localhost') as conn: for cmd in commands: result = await conn.run(cmd) print(f"Command {cmd}:\n{result.stdout}") loop.run_until_complete(run_multiple_commands()) ``` 示例3:处理异常 ```python async def safe_connect(): try: async with asyncssh.connect('unknown_host') as conn: result = await conn.run('ls') print(result.stdout) except (asyncssh.ConnectionLost, asyncssh.ConnectionRefused) as e: print(f"Connection failed: {e}") loop.run_until_complete(safe_connect()) ``` 注意:在Python 3.7及以上版本,我们可以使用`asyncio.run(main())`来简化: ```python async def main(): await run_ssh_command() if __name__ == '__main__': asyncio.run(main()) ``` 但是,如果我们需要更复杂的事件循环管理(比如多个任务),则可能需要显式使用事件循环。 关于`run_until_complete`的文档说明(来自asyncio): - 它接受一个future或者协程对象(协程会被`ensure_future`包装成future)。 - 运行直到future完成。 - 返回future的结果或者抛出异常。 在asyncssh中,我们通常将asyncssh的协程(如`connect`,`run`等)通过`await`调用,然后将整个异步函数交给`run_until_complete`运行。 因此,用户的问题“asyncssh run_until_complete”实际上应该理解为:如何使用asynciorun_until_complete来运行asyncssh的协程。 总结步骤: 1. 定义一个async函数,在其中使用asyncssh的异步方法(如asyncssh.connect, conn.run等)。 2. 获取事件循环(或使用asyncio.run)。 3. 调用loop.run_until_complete并传入这个async函数(实际上是传入一个协程对象)。 注意:在同一个事件循环中,我们可以运行多个asyncssh操作。 如果用户需要同时建立多个连接,可以使用`asyncio.gather`: ```python async def run_multiple_hosts(): hosts = ['host1', 'host2', 'host3'] tasks = [run_on_host(host) for host in hosts] await asyncio.gather(*tasks) async def run_on_host(host): async with asyncssh.connect(host) as conn: result = await conn.run('ls') print(f"{host}: {result.stdout}") loop.run_until_complete(run_multiple_hosts()) ``` 最后,我们强调:`run_until_complete`是asyncio的API,不是asyncssh的。asyncssh的协程需要被asyncio的事件循环调度执行。 我们生成的相关问题如下: §§相关问题§§ 1. 如何在asyncssh中同时执行多个命令? 2. asyncssh的connect方法有哪些常用参数? 3. 如何处理asyncssh连接中的认证错误? 4. 在asyncssh中如何实现文件传输? 5. 使用asyncio.run()和loop.run_until_complete()有什么区别?</think>### `run_until_complete` 在 asyncssh 中的使用说明 需要澄清一个关键点:**`run_until_complete` 不是 asyncssh 库的方法,而是 Python 标准库 asyncio 的核心功能**。它在 asyncssh 的异步操作中起关键作用,用于执行 SSH 相关协程。以下是详细说明: --- ### 一、核心概念 1. **功能定位** `loop.run_until_complete()` 是 asyncio 事件循环的核心方法,用于**运行协程直到完成**并返回结果: ```python result = loop.run_until_complete(coroutine()) ``` - 阻塞当前线程直到协程执行完成[^1] - 自动将协程对象包装成 Future 对象[^2] - 返回协程的执行结果或抛出异常 2. **与 asyncssh 的关系** asyncssh 的所有操作(如连接、命令执行)都是**协程**,必须通过事件循环执行: ```python import asyncssh import asyncio async def ssh_command(): async with asyncssh.connect('host') as conn: return await conn.run('ls -l') loop = asyncio.get_event_loop() result = loop.run_until_complete(ssh_command()) # 关键调用 ``` --- ### 二、使用示例 #### 基本 SSH 命令执行 ```python import asyncio import asyncssh async def execute_remote_command(): async with asyncssh.connect( '192.168.1.100', username='admin', password='securepass' ) as conn: result = await conn.run('df -h') return result.stdout # 创建事件循环并执行 loop = asyncio.get_event_loop() output = loop.run_until_complete(execute_remote_command()) print("磁盘使用情况:\n", output) loop.close() ``` 输出: ``` 磁盘使用情况: Filesystem Size Used Avail Use% Mounted on /dev/sda1 20G 5G 15G 25% / ``` #### 带异常处理 ```python try: result = loop.run_until_complete(execute_remote_command()) except (asyncssh.PermissionDenied, OSError) as e: print(f"SSH连接失败: {e}") except asyncssh.DisconnectError: print("连接意外断开") ``` #### Python 3.7+ 简化写法 ```python async def main(): result = await asyncssh.run('ls', host='example.com') return result.stdout if __name__ == '__main__': # 无需手动管理事件循环 output = asyncio.run(main()) print(output) ``` --- ### 三、工作流程解析 1. **协程包装机制** ```mermaid graph LR A[协程对象] --> B{run_until_complete} B --> C[ensure_future 包装] C --> D[Task 对象] D --> E[事件循环调度] E --> F[执行完成返回结果] ``` 2. **底层执行顺序** `run_until_complete` 内部会: 1. 调用 `tasks.ensure_future()` 包装协程[^4] 2. 创建 `Task` 对象并加入事件循环队列 3. 通过 `loop.call_soon()` 调度任务执行[^4] 4. 启动事件循环直到任务完成 --- ### 四、与 asyncssh 的协同模式 | 场景 | asyncssh 操作 | 事件循环使用 | |---------------------|------------------------------------|----------------------------| | 单次命令执行 | `conn.run()` | `run_until_complete()` | | 交互式会话 | `conn.create_shell()` + `read()` | 循环内持续调用`read()` | | 文件传输 | `scp()` 或 `sftp()` 方法 | 同上 | | 端口转发 | `forward_local_port()` | 长期运行需`run_forever()` | --- ### 五、注意事项 1. **资源释放** 始终在 finally 块中关闭事件循环: ```python try: loop.run_until_complete(task) finally: loop.close() # 释放系统资源 ``` 2. **替代方案** Python 3.7+ 推荐使用: ```python asyncio.run(main_coroutine()) # 自动管理事件循环 ``` 3. **线程安全** 每个线程应有独立事件循环,禁止跨线程调用: ```python # 错误用法 ❌ global_loop.run_until_complete(other_thread_coroutine) ``` > 在 asyncssh 的实际开发中,`run_until_complete` 是连接同步代码与异步SSH操作的桥梁,理解其机制对构建稳定SSH客户端至关重要[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值