流畅的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()
执行。