首先,协程是基于线程池实现的。有n个线程来完成m个协程。那么在操作系统看来,调度对象是n个线程。这方面协程与线程池无差别。
让出CPU的时机上,协程是由于异步IO或者任务结束而不再占用CPU,线程池中提交的任务也同样由于异步IO或者任务结束而不占用CPU。
任务中途挂起状态上,协程允许任务中间由于IO挂起,等到恢复到就绪状态后,可能被放到另一个线程上继续执行,这些调度过程是不需要干预的。线程池则不存在任务挂起状态,每个任务都必须一口气完成,如果某个任务中间出现了wait()这样让出CPU的操作,那么任务也不会被丢回到等待队列,而是继续占用线程资源。在使用线程池的时候,如果一个长期任务中间有让出CPU,那么应该将其分割成为不含让出CPU的小片段,再使用回调等方式逐步添加到任务队列。这里线程池远不如协程方便。
实际上,协程是线程池的自动调度任务的版本,自动根据任务状态将其剩余部分丢回到等待队列,免去了人工干预分割任务成各个片段的麻烦。协程需要由调度器管理任务状态,所以不像线程一样可以人工干预使其进入等待,也不再有必要暴露管理线程状态的接口。
从调度任务带来的性能上,如果使用相同数量的线程,合理地划分任务片段,实际上协程不会比线程池具有更好的性能。但是划分任务片段是个麻烦事,让任务调度看起来像JS的回调一样,只是把发起回调变成了提交任务片段。