协程
协和介绍
协和:是单线程下的并发,又称微线程,纤程。协和是一种用户态的轻量级线程,即协和是由用户程序自己控制调度的。
对于单线程下,我们不可避免程序出现io操作,但如果我们能在自己的程序中(即用户程序级别,而非操作系统级别)控制单线程下的多个任务能在一个任务遇到io阻塞 时就切换到另外一个任务去计算,这样就保证了该线程能够最大限度地处于就绪态,即都可以被cpu执行的状态,相当于我们在用户程序级别将自己的io操作最大限度地隐藏起来,从而可以迷惑操作系统,让其看到:该线程好像是一直在计算,Io比较少,从而更多的将cpu的执行权限分配给我们的线程。
协和的本质就是在单线程下,由用户自己控制一个任务遇到io阻塞了就切换另一个任务去执行,以此来提升效率。
1.python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或者执行时间过长就会被迫交出cpu执行权限,切换其他线程运行)
2.单线程内开启协和,一量遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效率(非io操作的切换与效率无关)
协程优点:
1.协和的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
2.单线程内就可以实现并发的效果,最大限度地利用cpu
协和缺点:
1.协和的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协和
2.协和指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
yield实现函数间的切换:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def func1(): print(1) yield print(3) yield def func2(): g = func1() next(g) print(2) next(g) print(4) func2()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def consumer(): while True: n = yield print('消费了一个包子%s'%n) def producer(): g = consumer() next(g) for i in range(10): print('生产了包子%s'%i) g.send(i) producer()
Greenlet模块
安装:pip3 install greenlet
Gevent是一个第三方库,可以通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenet,它是以C扩展模块形式接入Python的轻量级协和。Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import time from greenlet import greenlet def eat1(): print('吃鸡腿1') g2.switch() time.sleep(5) print('吃鸡腿2') g2.switch() def eat2(): print('吃饺子1') g1.switch() time.sleep(3) print('吃饺子2') g1 = greenlet(eat1) g2 = greenlet(eat2) g1.switch()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import gevent from threading import current_thread def func(): print(current_thread().name) print(123) gevent.sleep(1) print(456) def func2(): print(current_thread().name) print('wawawa') gevent.sleep(1) print('hahaha') g1 = gevent.spawn(func) g2 = gevent.spawn(func2) gevent.joinall([g1,g2])
Gevent同步与异步对比
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from gevent import monkey;monkey.patch_all() import time # time socket urllib requests import gevent # greenlet gevent在切换程序的基础上又实现了规避IO def task(args): time.sleep(1) print(args) def sync_func(): # 同步 for i in range(10): task(i) def async_func(): # 异步 g_l = [] for i in range(10): g_l.append(gevent.spawn(task,i)) # 给写成任务传参数 gevent.joinall(g_l) start = time.time() sync_func() print(time.time() - start) start = time.time() async_func() print(time.time() - start)
协和应该:爬虫
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from gevent import monkey;monkey.patch_all() import time import gevent import requests def get_url(url): res = requests.get(url) print(url,res.status_code,len(res.text)) url_lst =[ 'http://www.sohu.com', 'http://www.baidu.com', 'http://www.qq.com', 'http://www.python.org', 'http://www.cnblogs.com', 'http://www.mi.com', 'http://www.apache.org', 'https://www.taobao.com', 'http://www.360.com', 'http://www.7daysinn.cn/' ] start = time.time() for url in url_lst: get_url(url) print(time.time() - start)