协程

协程,又叫微线程。协程是一种用户态的轻量级线程。
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。协程能保留上一次调用的时候的状态,每次过程重入时,相当于进入上一次调用的状态。换种说法,进入上一次离开时所处的逻辑流的位置。
 
优势:
无需线程上下文切换的开销
无需原子操作锁定及同步的开销(就是不用锁)
方便切换控制流,简化编程模型
高并发,高扩展,低成本,一个cpu支持上万协程也没问题
 
缺点:
无法利用多核资源,协程本质上是单线程,也不能使用单个CPU的多核
进行阻塞(Blocking)操作会阻塞掉整个程序 
 
手动挡协程实例,需要提前安装greenlet模块:
# -*- coding:utf-8 -*-
# Author:Brownyangyang
from greenlet import greenlet

def test1():
    print(12)
    gr2.switch()
    print(34)
    gr2.switch()

def test2():
    print(56)
    gr1.switch()
    print(78)

gr1 = greenlet(test1)  #启动协程
gr2 = greenlet(test2)
gr1.switch() #第一步,先执行gr1

自动挡实例,需要安装gevent第三方库:

# -*- coding:utf-8 -*-
# Author:Brownyangyang
import gevent
def foo():
   print('Running in foo')
   gevent.sleep(2)
   print('Explicit context switch to foo again')

def bar():
   print('Explicit context to bar')
   gevent.sleep(1)
   print('Implicit context switch back to bar')

def func3():
   print("running func3")
   gevent.sleep(0)
   print("running func3 again")

gevent.joinall([
gevent.spawn(foo),
gevent.spawn(bar),
gevent.spawn(func3)
])  ##启动三个协程

遇到gevent.sleep就切换

使用协程爬网页:

# -*- coding:utf-8 -*-
# Author:Brownyangyang
from urllib import request
import gevent
from gevent import monkey
#gevent默认识别不了urllib和socket的IO操作,所以要导入monkey

monkey.patch_all()
#把当前程序的所有IO操作单独记上标记
def f(url):
   print('GET:%s' % url)
   resp = request.urlopen(url)
   data = resp.read()
   print("%d bytes received from %s"% (len(data),url))
   f = open("url.html","wb")
   f.write(data)
   f.close()
   print('%d bytes received from %s.' %(len(data),url))

   gevent.joinall([
      gevent.spawn(f,'https://www.python.org/'),
      gevent.spawn(f,'https://www.yahoo.com/'),
      gevent.spawn(f,'https://github.com/'),
   ])
原文地址:https://www.cnblogs.com/brownyangyang/p/8926478.html