文章目录

  • 协程
  • 一、协程基本概述
  • 二、用生成器 yiled 实现协程
  • 三、greenlet
  • 四、gevent
  • 补充: mokey补丁模块


协程

一、协程基本概述

协程 又称为微线程,纤程,英文名(corotine)。从技术的角度来说,“协程就是你可以暂停执行的函数”。可以理解成生成器一样。一句话总结协程就是一个线程里可以协调cpu来完成多任务,提高效率,减少资源的浪费。

协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程(单线程),在一个线程中规定某个代码块执行顺序。

协程的使用场景:当程序中存在大量不需要CPU操作的时(IO),适用协程;

协程工作原理如下图:

python 协成socket python协程用法_单线程

二、用生成器 yiled 实现协程

1、创建 work1 生成器。

2、创建work2 生成器

3、获取生成器,用next() 运行生成器

import time
def work1():
    while True:
        print("------我是work1------")
        time.sleep(1)
        yield   #程序碰见 yield 会返回一个生成器。
def work2():
    while True:
        print("------我是work2------")
        time.sleep(1)
        yield
if __name__ == '__main__':
    while True:
        next(work1())
        next(work2())

三、greenlet

greenlet 是第三方模块。使用greenlet 可以实现协程,可以自行调度微线程,即协程。generator 实现的协程在yiled value 时只能将 value返回给调用者(caller)。而在greenlet中,target.switch(value)可以切换到指定的协程(target),然后yield value。greenlet 用switch 来表示协程的切换,从一个协程切换到另一协程需要显示指定。

greenlet 实现协程的步骤:

1、导入模块 from greenlet import greenlet

2、创建任务 work1 work2

3、创建greenlet 的对象。 g1 = greenlet(work1) ,g2 = greenlet(work1)

4、切换任务 work1里(g2.switch), work2(g1.switch) 两个任务来回切换。

import time
from greenlet import greenlet
def work1():
    while True:
        print("------我是work1------")
        time.sleep(1)
        g2.switch()
def work2():
    while True:
        print("------我是work2------")
        time.sleep(1)
        g1.switch()
if __name__ == '__main__':
    g1 = greenlet(work1)
    g2 = greenlet(work2)
    g1.switch()

四、gevent

greenlet 已经是实现了协程,但是这个还需要人工切换,有点麻烦。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent 为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

grevent也是第三方库。

如何用gevent 实现协程:

1、导入gevent 模块 improt gevent

2、指派任务 gevent.spawn(函数名,参数1,参数2,…) g1 = gevent.spawn(work1)。g1.join , g2.join 让主线程等待程序完成后退出(让程序阻塞)。

有一个耗时操作,1.gevent.sleep(0.5)替换 time.sleep(0.5);2.打补丁让gevent 识别 time.sleep()。

打补丁是在不修改程序源代码的情况下,为程序增加新的功能。

补充: mokey补丁模块

如何打补丁:1) 导入 monkey 模块 from gevent import monkey

2)破解所有补丁 monkey.patch_all()

猴子补丁主要有以下几个用处:

1、在运行时替换方法、属性等

2、在不修改第三方代码的情况下增加新的功能

3、在运行时为内存中的对象增加patch而不是在磁盘的源代码中增加。

#导入模块
from gevent import monkey
#破解所有
monkey.patch_all()
from gevent import monkey   #导入monkey 补丁模块
monkey.patch_all()
import time
import gevent
def work1():
    while True:
        print("------我是work1------",gevent.getcurrent()) #gevent.getcurrent()  查看哪个协程在执行
        # gevent.sleep(1)
        time.sleep(1)

def work2():
    while True:
        print("------我是work2------",gevent.getcurrent())
        # gevent.sleep(1)
        time.sleep(1)
if __name__ == '__main__':
    g1 = gevent.spawn(work1)
    g2 = gevent.spawn(work2)
    # 让主线程等待程序完成后退出,(让程序阻塞)
    g1.join()
    g2.join()