协程

协程Coroutine

协程的目的

​ **要在单线程下实现并发,在应用程序里控制多个任务 切换 + 保存(本质) **

并发: 指的是多个任务同时发生,看似好像是同时进行,其实是切换进行
并行: 指的是多个任务真正的同时进行

并发 = 切换 + 保存

优点:
应用程序(自己操作)级别的切换速度要快于操作系统的切换速度

缺点:
多个任务一旦有一个阻塞没有切,整个线程都阻塞,该线程内的其他的任务都不能执行.

一旦引入协程,就需要检测单线程下的所有IO,实现遇到IO就切换
因为有一个任务阻塞了,整个线程都阻塞了,即便是纯计算也要阻塞.

总结协程特点:

  • 必须在只有一个单线程里实现并发
  • 修改共享数据不需要加锁
  • 用户程序里自己保存多个控制流的上下文栈
  • 一个协程遇到IO操作自动切换到其它协程(如何实现检测IO? yield,greenlet都无法实现, 就用到了gevent模块)

进程的流程:

线程的流程:

协程的流程:

Greenlet

"""
    使用greenlet模块可以简单完成多个任务之间的切换(使用yield生成器的方式过于麻烦)
"""
# greenlet(run=None, parent=None): 创建一个greenlet实例
# g.parent: 每个协程都有一个父协程,当前协程结束后会回到父协程中执行,该属性默认是创建该协程的协程
# g.run : 该属性是协程实际运行的代码,run方法结束了,那么该协程也结束了
# g.switch(*args, **kwargs): 切换到g 协程
# g.throw() :切换到g协程, 接着抛出一个异常

from greenlet import greenlet


def eat(name):
    print('%s est 1' % name)
    g2.switch('kp')
    print('%s eat 2' % name)
    g2.switch()


def play(name):
    print('%s play 1' % name)
    g1.switch()
    print('%s play 2' % name)
    

g1 = greenlet(eat)
g2 = greenlet(play)

g1.switch('kopa')
# kopa est 1
# kp play 1
# kopa eat 2
# kp play 2



Gevent介绍

Gevent是一种基于协程的Python网络库, 用到Greenlet提供的,封装了libevent事件循环的高层同步API. 用同步的方式写异步IO的代码.

使用Gevent的新能比一般的线程高, 但是也有坑:

1, Monkey-patching, 称之为猴子补丁, 因为如果使用了这个补丁,Gevent直接修改标准库里面大部分的阻塞式系统调用, 包括socket,threading和select等模块, 而变成协作式运行. (可能导入补丁会有其他问题)

2, 第三方库支持

"""
    g1 = gevent.spwan(func,*args, **kwargs) :
        第一个参数是函数名,如eat,后面可以跟参数,参数是传给eat的

    g.join() : 等待g 结束

    gevent.joinall([g1, g2]) : 等待g1, g2 结束

    g.value : 拿到返回值


"""
# 猴子补丁放在要补丁的前面(可以看成放在最前面)
from gevent import monkey
monkey.patch_all()

import gevent
import time

def eat():
    print('eat food 1')
    time.sleep(1)
    print('eat food 2')

def play():
    print('play 1')
    time.sleep(1)
    print('play 2')

g1 = gevent.spawn(eat)
g2 = gevent.spawn(play)
gevent.joinall([g1, g2])
print('zhu')

# eat food 1
# play 1
# eat food 2
# play 2
# zhu
原文地址:https://www.cnblogs.com/kp1995/p/10222482.html