流畅的Python - 第18章-使用asyncio处理并发
Contents
线程与协程对比
线程处理任务时,所有的线程争抢CPU的资源;协程处理任务时,由单线程完成,所有的任务都有序的安排在未来进行执行。

书上的示例主要讲了实现动画形式显示文本式旋转指针,线程和协程两种不同的方式。
线程方面,主要使用了threading模块中的Thread方法创建线程并执行。注意的一点是,python中的线程不提供终止线程的API,所以需要给线程发送消息才能关闭线程,如此例中的signal.go属性。
 |  | 
通过asyncio模块创建协程的要求比较多。
- 首先需要有一个
事件循环,使用asyncio.get_event_loop()产生。 - 然后使用
run_until_complete将协程注册到事件循环中。run_until_complete接收Future对象或者Task任务(为Future对象的子类),也可以接收普通的协程,默认会将协程封装成Task。 - task对象可以使用
loop.create_task(supervisor())实现,也可以使用asyncio.ensure_future(supervisor())实现。 - 最后全部任务执行完后返回所有的结果,
run_until_complete接收什么参数,就返回对应参数返回的结果。如果传入的是wait_coro,则返回wait_coro对象所做的事,返回一个元组。 
 |  | 
线程方式与协程方式的对比如下:
- 协程中不建议使用
time.sleep(...)来进行时间的等待,会引起阻塞。推荐的是使用await asyncio.sleep(...)代替。 - 用于驱动协程的
Task对象不能由自己动手实例化,而是通过把协程传给async.async(...)函数或者loop.create_task(...)方法获取。获取完后的Task对象的执行时间已经确定!在线程中,必须调用start()方法才能运行线程。 - 线程不能通过外部的API进行停止,协程可以通过使用
Task.cancel()实例方法,在协程内部抛出asyncio.CancelledError异常,协程可以在暂停的yield处捕获此异常进行退出操作。 - 在协程中,supervisor()函数(或者task对象)必须由
loop.run_until_complete()执行。