一些基本概念
event_loop 事件循环:程序开启一个无限的循环,程序员会把一些函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。
coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。
task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含任务的各种状态。
future: 代表将来执行或没有执行的任务的结果。它和task上没有本质的区别
定义一个协程
定义协程很简单,使用python3.5的关键字async,可以像定义普通的函数一样:
|
|
使用async定义一个协程(coroutine),协程也是一种对象。协程不能直接运行,需要把协程加入到事件循环(loop),由后者在适当的时候调用协程。curio
使用curio kernel
来运行协程,run()方法可以开始kernel并且初始化Task。
创建一个task
协程对象不能直接运行,在运行kernel
的时候,可以curio.spawn方法将协程包装成为了一个任务(task)对象。所谓task对象是Future类的子类。保存了协程运行后的状态,用于未来获取协程的结果。
|
|
在当前程序中,parent()使用curio.spawn()创建新的子任务,当sleep一段时间后,countdown开始运行,join()方法会等待这个Task运行结束,在首先等待countdown()
完成后,然后程序等待kid()完成,在你运行这个程序时,可以得到下面的结果:
|
|
curio monitor
在上个程序中的kid()将会阻塞1000秒,而parent的join方法会等待kid()的完成后才会结束。你可以将代码改成下面的样子来开启monitor:
|
|
运行程序,当程序阻塞在kid()的时候,打开monitor工具:
|
|
使用ps
命令查看:
|
|
还可以使用where
查看追踪task:
|
|
可以直接取消kid():
|
|
这样手动取消task会抛出TaskCancelled异常,表示程序没有正常运行。因此你需要结束task的时候需要在程序中手动取消:
|
|
当然,你在parent
取消kid
的时候,kid
可以捕捉到这个消除请求并且清除它:
|
|
同步机制
curio模块包含多种同步机制,它提供和线程一样的同步机制(Event, Lock, Semaphore, and Condition
)。看下面使用Event的例子:
|
|
在程序运行kid()的时候,await start_evt.wait()
会等待,直到await start_evt.set()
运行。