-
Python中的异步编程
Python实现异步编程的方案有:
twisted
:使用事件驱动机制来提升python性能gevent
:使用greenlet在用户态完成栈和上下文切换来减少切换带来的性能损耗tornado
:使用生成器来保存协程上下文及状态,使用原生的python语法实现了协程asyncio
:异步编程标准化。
-
Python异步编程的特点
- 单线程、异步阻塞
- 异步的实现基于协程,不仅使得Python中的异步是阻塞的,而且最小执行单位不再是单个任务,而是每个任务的一部分。
-
Python高并发方案的区别
多进程、多线程这类方案,IO的调度取决于系统;
协程,调度来自于用户。
asyncio模块实现异步,也是采用协程实现。
-
asyncio模块的主要组件和概念
- 事件循环:asyncio模块中,每一个进程都有一个事件循环。程序员把一些函数注册到事件循环上,当满足事件发生的时候,调用相应的协程函数;
- 协程:子程序的泛化概念,可以在执行期间暂停,等待外部的处理完成之后,从之前暂停的地方回复执行。理解为一个使用async关键字定义的函数。它的调用不会立即执行,而是会返回一个协程对象,协程对象需要注册到事件循环,由事件循环调用;
- Futures:定义Future对象,表示尚未完成的计算;
- Tasks:用于封装和管理并行模式下的协程;协程对象是一个可以挂起的函数,任务则是对协程进一步封装,其中包含任务的各种状态;
- async/await关键字:定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。
-
事件循环Event loop(维基百科)
事件的本质就是异步。
事件源:可以产生事件的实体;
事件处理者:能处理事件的实体;
事件循环:第三方实体。
事件循环的作用是管理所有的事件,在整个程序运行过程中不断循环执行,追踪事件发生的顺序将它们放到队列中,当主线程空闲的时候,调用相应的事件处理者处理事件。
-
协程与事件循环案例
import asyncio import time async def do_some_work(x): # async关键字定义一个协程 print('Waiting:', x) coroutine = do_some_work(2) # 协程的调用不会直接执行,而是返回一个协程对象 loop = asyncio.get_event_loop() # 创建一个事件循环 loop.run_until_complete(coroutine) # run_until_complete将协程注册到事件循环,并启动事件循环。
协程对象不能直接运行,在注册事件循环时,
run_until_complete
将协程包装成了一个task
。task
对象是Futurn
类的子类,保存了协程运行后的状态,用于未来获取协程的结果。import asyncio import time async def do_some_work(x): # async关键字定义一个协程 print('Waiting:', x) coroutine = do_some_work(2) # 协程的调用不会直接执行,而是返回一个协程对象 loop = asyncio.get_event_loop() # 创建一个事件循环 task = loop.create_task(coroutine) # 创建task,此时的task尚未加入事件循环,状态为pending loop.run_until_complete(task) # run_until_complete将task注册到事件循环,并启动事件循环。 # task执行完后,状态为finished
run_until_complete
参数是一个future对象
,当传入的是:- 协程,会自动封装成
task
task
,task
是Future
的子类。asyncio.ensure_future(coroutine)
和loop.create_task(coroutine)
都可以创建task
# 绑定回调函数 import asyncio import time async def do_some_work(x): # async关键字定义一个协程 print('Waiting:', x) return 'Done after {}s'.format(x) # 返回值 def callback(future): # 定义一个回调函数,最后一个参数是future对象,如果这里有多个参数,下方通过偏函数导入 print('Callback: ', future.result()) # 返回future的结果 coroutine = do_some_work(2) # 协程的调用不会直接执行,而是返回一个协程对象 loop = asyncio.get_event_loop() # 创建一个事件循环 task = loop.create_task(coroutine) # 创建task,此时的task尚未加入事件循环,状态为pending task.add_done_callback(callback) # 绑定回调函数,在task执行完毕的时候获取执行的结果 loop.run_until_complete(task) # run_until_complete将task注册到事件循环,并启动事件循环。 # task执行完后,状态为finished
coroutine执行结束时会调用回调函数,并通过参数future获取协程执行的结果,此future是没有传入的,实际上与创建的task是同一个对象
# 阻塞和await import asyncio import time now = lambda: time.time() async def do_some_work(x): print('Waiting: ', x) await asyncio.sleep(x) # 执行sleep时,await使此协程主动让出控制权,loop调用其他协程 return 'Done after {}s'.format(x) start = now() coroutine = do_some_work(2) loop = asyncio.get_event_loop() task = asyncio.ensure_future(coroutine) loop.run_until_complete(task) print('Task ret: ', task.result()) print('TIME: ', now() - start) # 以上还只有一个协程,让出控制权也暂时无用,如果有多个协程,协程A让出控制权,loop就会把控制权分配给协程B,实现了并发。 # asyncio实现并发:每当一个协程任务阻塞的时候就await,让后其他协程继续工作。 import asyncio import time now = lambda: time.time() async def do_some_work(x): print('Waiting: ', x) await asyncio.sleep(x) return 'Done after {}s'.format(x) start = now() coroutine1 = do_some_work(1) coroutine2 = do_some_work(2) coroutine3 = do_some_work(4) tasks = [ asyncio.ensure_future(coroutine1), asyncio.ensure_future(coroutine2), asyncio.ensure_future(coroutine3) ] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) # asyncio.wait(接收task列表);asyncio.gather(接收多个task) for task in tasks: print('Task ret: ', task.result()) print('TIME: ', now() - start)
- 协程,会自动封装成
-
How the heck does async/await work in Python 3.5?
From Wikipedia, an eventloop is a programming construct that waits for and dispathches enents or messages in a program.Basically an event loop lets you go, “When A happens, do B”.
In Python’s case,
asyncio
was added to the standard library to provide an event loop. -
Reference
理解Python异步中的事件循环(asyncio管理事件循环)
最新推荐文章于 2024-08-14 10:14:20 发布