在Python中,协程是一种用于处理并发任务的轻量级线程。它们允许你在一个线程中执行多个任务,而不需要创建多个线程或进程。
概览
定义:协程是一个可以暂停和恢复的函数。你可以使用
async def来定义一个协程。异步执行:协程通过
await关键字来等待其他协程的完成,而不会阻塞整个程序。这意味着你可以在等待某个操作(如网络请求)时,继续执行其他任务。事件循环:Python使用事件循环来管理协程的执行。事件循环会调度和运行协程,确保它们在合适的时机被执行。
示例:
import asyncio async def say_hello(): print("Hello") await asyncio.sleep(1) # 模拟异步操作 print("World") async def main(): await say_hello() asyncio.run(main())
在这个例子中,say_hello是一个协程,它会打印“Hello”,然后等待1秒(模拟异步操作),最后打印“World”。asyncio.run(main())启动事件循环并运行main协程。
await
await关键字用于等待另一个协程的完成或一个可等待对象(如异步I/O操作)。使用await的主要目的是让协程在等待某个操作时能够“暂停”,并允许事件循环去执行其他任务,从而提高程序的效率。
以下情况会使用await:
等待异步操作:当你需要执行一个异步操作(如网络请求、文件I/O等)并希望在操作完成之前不阻塞其他任务时,使用
await。调用其他协程:当你在一个协程中调用另一个协程时,应该使用
await来确保调用的协程在完成之前不会继续执行后面的代码。
什么情况不用await:
print是一个普通的同步函数,它会立即执行并输出内容。它不涉及任何异步操作,因此不需要使用await。在协程中,只有那些返回可等待对象的操作(如asyncio.sleep()、网络请求等)才需要使用await。
示例说明:
import asyncio
async def say_hello():
print("Hello") # 这里不需要await,因为print是同步的
await asyncio.sleep(1) # 这里需要await,因为这是一个异步操作
print("World")
async def main():
await say_hello()
asyncio.run(main())在这个例子中,第一次print("Hello")会立即执行,而await asyncio.sleep(1)会让协程暂停1秒,期间事件循环可以执行其他任务。最后,print("World")在等待结束后执行。
如何判断对象是否是可等待的(await)
在Python中,通常可以通过以下几种方式来判断一个函数是否返回可等待对象(即可以使用await的对象):
查看文档:大多数库和框架的文档会明确说明哪些函数是异步的,并且返回可等待对象。查阅官方文档是了解函数行为的最佳方式。
函数定义:如果一个函数是用
async def定义的,那么它返回的就是一个协程对象,可以被await。例如:async def my_coroutine(): pass使用
inspect模块:Python的inspect模块可以用来检查对象的类型。你可以使用inspect.iscoroutinefunction()来判断一个函数是否是协程函数,或者使用inspect.isawaitable()来判断一个对象是否是可等待的。例如:import inspect async def my_coroutine(): pass print(inspect.iscoroutinefunction(my_coroutine)) # 输出: True常见的异步库:许多流行的库(如
asyncio、aiohttp、asyncpg等)提供的函数通常是异步的。你可以查看这些库的文档,了解哪些函数是异步的。使用
asyncio的isawaitable:你可以使用asyncio.isawaitable()来检查一个对象是否是可等待的。例如:import asyncio async def my_coroutine(): return 42 result = my_coroutine() # 返回一个协程对象 print(asyncio.isawaitable(result)) # 输出: True
如何理解一个程序的可等待架构
为什么Telethon用协程呢?
它使用异步编程的主要原因是为了提高性能和响应能力。我们可以想象作为一个telegram的客户端,
它可能在你上传文件的同时, 也会收到别人给你的信息提醒. 这就是异步.
如果有这样的需求, 那么用异步协程是最好的选择.