概念
协程,英文为coroutine,又称微线程,纤程,是一种用户态的轻量级线程。
子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。
所以子程序是通过栈实现的,一个线程就是执行一个子程序。
子程序的调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同,协程看上去也是子程序,但在执行过程中子程序可中断,在适当的时候再返回接着执行(强调的是自由切换)。
注意:在一个子程序中中断,去执行其他子程序,不是子程序调用,而是有点类似cpu调用。
协程的特点在于是一个线程执行。
协程的作用
在执行函数A时,可以随时中断,去执行函数B,然后中断继续执行函数A(可以自由切换)。但这一过程并不是函数调用(没有调用语句),这一整个过程看似像多线程,然而协程只有一个线程执行。
协程和线程的比较
1 协程的执行效率高,由于协程执行过程中子程序的切换是由自己控制,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就更明显。
2 不需要线程的锁机制,因为只有一个线程,不存在同时修改冲突,所以在协程控制共享资源不加锁,只需要判断状态就好了,所以执行效率要比线程高。
3 多线程通过cpu切片来切换多线程的执行,而多协程则是由设计者自己来设置执行顺序。
如何利用协程的优势
由于协程是一个线程执行,那么如何利用多核cpu呢?
最好的做法是 多进程+协程 ,即利用了多核cpu,有利用了协程的执行效率,可获得极高的性能。
协程的适用场景
协程可以处理I/o密集型程序的效率问题。
协程的代码
以python3.x主:
1 gevent gevent是第三方库(先保留,目前已python标准库为主)
2 asyncio + yield from (python 3.4)
asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。asyncio的异步操作,需要在coroutine中通过yield from完成。
import asyncio
@asyncio.coroutine
def test(i):
print("test_1", i)
r = yield from asyncio.sleep(1)
print("test_2", i)
loop = asyncio.get_event_loop()
tasks = [test(i) for i in range(5)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
运行结果:
3 asyncio + async/await(python3.5)
为了简化并更好地标识异步IO,从Python 3.5开始引入了新的语法async和await,可以让coroutine的代码更简洁易读。
请注意,async和await是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:
- 把@asyncio.coroutine替换为async;
- 把yield from替换为await。
所以以上代码可以改为:
import asyncio
async def test(i):
print("test_1", i)
await asyncio.sleep(1)
print("test_2", i)
loop = asyncio.get_event_loop()
tasks = [test(i) for i in range(5)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
运行结果:
可以看到两次的运行结果虽然相同,但是tasks = [test(0), test(1), test(2), test(3), test(4)],为什么不是顺序执行的呢?
协程中的执行顺序是不确定的,实际上,几乎所有的协程都是在同一个循环中迭代的,几乎在同一时间启动。整个过程执行时间很容易遇到线程上下文切换从而改变执行的先后顺序,但这个过程并不是随机的, 但同一台机器上很可能多次重复的都是同一种顺序.