是一种轻量级的线程, 由程序自己控制调度的 线程是内核级的, 协程是程序级别的
优点:
协程的切换开销小,操作系统完全感知不到, 单线程内就可以实现并发效果,最大限度的 利用 CPU
协程遇到 IO 就自动切换到其他协程 检测 IO yield greenlet 无法实现
用 gevent 模块(select 机制) 实现 IO 的切换
伪并行,遇到IO就切换,单核下多个任务之间切换执行,给你的效果就是貌似你的几个程序在同时执行.提高效率
任务切换 + 保存状态
多核cpu,真正的同时执行
一个任务执行完在执行另外一个任务
import time
'''串行 用时'''
def func1():
    time.sleep(1)
    c = 0 
    for i in range(1000):
        c = i ** i
    print("func1>>", c)
def func2():
    time.sleep(2)
    c = 0
    for i in range(1000):
        c = i ** i
    print("func2>>", c)
if __name__ == '__main__':
    s_t = time.time()
    func1()
    func2()
    print(time.time() - s_t)  # 3.0608773231506348'''基于yield并发执行,多任务之间来回切换,这就是个简单的协程的体现,但是他能够节省I/O时间吗?不能'''
def func1():
    while 1:
        time.sleep(1)
        x = yield
        print("接收了%s 个任务" % x)
def func2():
    f = func1()
    # 找到 第一个 yield
    next(f)
    for i in range(1, 11):
        f.send(i)
        print("发送了 %s 个任务" % i)
s_t = time.time()
# 基于yield保存状态,实现两个任务直接来回切换,即并发的效果
# PS: 如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.
func2()  # 我在当前线程中只执行了这个函数,但是通过这个函数里面的send切换了另外一个任务
print(time.time() - s_t)  # 11.003206253051758
# 串行的执行 方式
# func1()
# func2()
# print(time.time() - s_t)  # 11.00475525856018
import time
from greenlet import greenlet
def eat(name):
    print('%s eat 1' % name)  # 2
    time.sleep(3)
    g2.switch('taibai')  # 3
    print('%s eat 2' % name)  # 6
    g2.switch()  # 7
def play(name):
    print('%s play 1' % name)  # 4
    time.sleep(3)
    g1.switch()  # 5
    print('%s play 2' % name)  # 8
g1 = greenlet(eat)
g2 = greenlet(play)
g1.switch('taibai')  # 可以在第一次switch时传入参数,以后都不需要import gevent
from gevent import monkey
monkey.patch_all()   # 补丁 识别所有的 IO 阻塞   time.sleep()  就可以用了
import time
def func1(name):
    print(name, 111111111)
    time.sleep(1)
    # gevent.sleep(1)
    print(name, 2222222222)
    return 123
def func2(name):
    print(name, 111)
    # gevent.sleep(1)  # time.sleep() 识别不到
    time.sleep(1)
    print(name, 222)
g1 = gevent.spawn(func1, "egen")  # 异步执行这个func1任务,后面egon就是给他传的参数
print(g1.value)  # 取出返回值的 结果
g2 = gevent.spawn(func2, "two")
# 此 方法 不用 单独 指定 join()
gevent.joinall([g1, g2])
print("aaaaaa")
################################################################
def task(pid):
    """
    Some non-deterministic task
    """
    time.sleep(0.5)
    print('Task %s done' % pid)
def synchronous():
    for i in range(10):
        task(i)
def asynchronous():
    g_l = [gevent.spawn(task, i) for i in range(10)]
    gevent.joinall(g_l)
if __name__ == '__main__':
    print('Synchronous:')  # 同步的 并发 执行
    synchronous()
    print('Asynchronous:')  # 异步的 并行 执行
    asynchronous()
# 上面程序的重要部分是将task函数封装到Greenlet内部线程的gevent.spawn。 初始化的greenlet列表存放在数组threads中,此数组被传给gevent.joinall 函数,后者阻塞当前流程,并执行所有给定的greenlet。执行流程只会在 所有greenlet执行完后才会继续向下走。
原文:https://www.cnblogs.com/zhang-zi-yi/p/10755813.html