线程是系统级别的,它们是由操作系统调度;协程是程序级别的,由程序员根据需要自己调度。我们把一个线程中的一个个函数叫做子程序,那么子程序在执行过程中可以中断去执行别的子程序;别的子程序也可以中断回来继续执行之前的子程序,这就是协程。也就是说同一线程下的一段代码<1>执行着执行着就可以中断,然后跳去执行另一段代码,当再次回来执行代码块<1>的时候,接着从之前中断的地方开始执行。
优点:
- 极高的执行效率,因为子程序切换而不是线程切换,没有了线程切换的开销;
- 不需要多线程的锁机制,因为只有一个线程在执行;
并没有说协程就一定不加锁,协程本身的某些功能实现也是通过线程池实现的;就算没有用到其他线程,假如一个操作需要连续性地完成,那么也是需要借助锁的概念。asyncio 和 gevent 库中都有实现 threading 下的一些同步机制,比如 lock、semaphore 等,虽然和 threading 的底层的实现不同,但是同样起到了保证一些操作顺序、不会被打断地执行。
gevent: (实现遇到io自动切换)
gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是greenlet, 它是以c扩展模块形式接入python的轻量级协程。 greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
gevent是一个基于协程(coroutine)的python网络函数库,通过使用greenlet提供了一个在libev事件循环顶部的高级别并发api。
主要特性有以下几点:
基于libev的快速事件循环,linux上面的是epoll机制
基于greenlet的轻量级执行单元
api复用了python标准库里的内容
支持ssl的协作式sockets
可通过线程池或c-ares实现dns查询
通过monkey patching功能来使得第三方模块变成协作式
monket patching
python的运行环境允许我们在运行时修改大部分的对象,包括模块、类甚至函数。虽然这样做会产生“隐式的副作用”,而且出现问题很难调试,但在需要修改python本身的基础行为时,monkey patching就派上用场了。monkey patching能够使得gevent修改标准库里面大部分的阻塞式系统调用,包括socket,ssl,threading和select等模块,而变成协作式运行。
semaphore和boundedsemphore 都是信号量类, 有进/线/协程获得信号量时(即acquire())计数器-1,释放信号量时(release())技术器 1,计数器为0的时候其他线/进/协程就被阻塞无法获得信号量。当计数器为设定好的上限的时候boundedsemaphore就无法进行release()操作,semaphore没有这个限制。