Python学习第52天(协程)

  关于协程,最早出现在处理io密集型和计算密集型问题中,出现过多进程加协程的处理模式,首先关于协程,其本质就是一个微线程。

  先说一下之前我们学到的线程和进程,这两者有一个非常明显和共同的特点,都属于抢占式程序,之间的切换是完全不受我们控制的,执行切换过程是属于操作系统级别的操作,所以与之对应,协程就出现了,其实协程的本质就是在你控制下进行线程之间的切换,其实我们在之前的生成器部分有讲到一个yield,就有类似的效果。

  先来回顾一下yield的使用方法吧

def f():
    print('hello world 1')
    yield
    print('hello world 2')
    yield
    print('hello world 3')

gen = f()
print(type(gen)) gen.
__next__() gen.__next__() gen.__next__()

  当含有yield的函数在最初运行的时候,预运行的时候会被系统识别,正式开始运行的时候,不是直接开始输出其中的语句,而是生成一个生成器,随后我们可以通过内置方法next()或者__next__()方法调用,每调用一次就会输出到yield处,随后保存运行的状态,待下一次运行next()的时候继续从上一次的next处向下运行,遇到下一个yield时保存状态,停止运行,同时yield也有return的功能,同样可以返回参数。

  其实yield的功能是类似于我们的协程的,所以我们先试用yield实现以下协程的功能。

import time
import queue

def consumer(name):
    print("--->ready to eat baozi...")
    while True:
        new_baozi = yield
        print("[%s] is eating baozi %s" % (name,new_baozi))
        #time.sleep(1)

def producer():

    r = con.__next__()
    r = con2.__next__()
    n = 0
    while 1:
        time.sleep(1)
        print("\033[32;1m[producer]\033[0m is making baozi %s and %s" %(n,n+1) )
        con.send(n)
        con2.send(n+1)

        n +=2


if __name__ == '__main__':
    con = consumer("c1")
    con2 = consumer("c2")
    p = producer()

  虽然能够基本实现,但是我们在实际操作的过程总不能每切换一次就是用一次next吧,太麻烦了,所以我们引入了greenlet模块

  greenlet是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator

  看一下实例吧。

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()

  虽然比yield好了很多,可以实现任意函数之间的切换,但是每次切换都需要人为的操作,不好不好,所以我们也要引入不用自己切换的这种模式。

  gevent模块

import gevent

import requests,time


start=time.time()

def f(url):
    print('GET: %s' % url)
    resp =requests.get(url)
    data = resp.text
    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://www.baidu.com/'),
        gevent.spawn(f, 'https://www.sina.com.cn/'),

])

# f('https://www.python.org/')
#
# f('https://www.yahoo.com/')
#
# f('https://baidu.com/')
#
# f('https://www.sina.com.cn/')

print("cost time:",time.time()-start)

  大致就是这个样子的,这就有点类似多线程的时候了,所以我们可以综合使用嘛。

  现在可以总结一下协程的优势了:

    优点1: 协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

    优点2: 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

    因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。

以上就是主要内容部分,其实前面的知识现在开始忘的连点印象都没有了,所以,复习复习,很重要。

最近工作也需要自己投入更多,加油加油。

猜你喜欢

转载自www.cnblogs.com/xiaoyaotx/p/12702498.html