zoukankan      html  css  js  c++  java
  • python进程和线程(六)

    协程

            协程,又称微线程,纤程。英文名Coroutine。顾名思义,协程是协作式的,也就是非抢占式的程序(线程是抢占式的)。协程的关键字是yield,一看到这个就想到了生成器对不对?那就顺便回顾一下生成器的知识点,只要叫什么器的,那肯定就是函数形式,生成器也是函数,只不过多了一个yield在函数中:

    def foo():
        print('ok')
        yield
    
    foo()

            猜一下foo()执行我的结果是什么?结果是什么都不会打印,为什么呢?打印foo()是什么看一下:

    # -*- coding: utf-8 -*-
    
    def foo():
        print('ok')
        yield
    
    gen = foo()
    print(gen)
    
    >>><generator object foo at 0x000001AE31BCA318>

             原来foo()是一个生成器函数,只能通过next放方法执行了。

    # -*- coding: utf-8 -*-
    
    def foo():
        print('ok')
        yield
    
    gen = foo()
    # print(gen)
    gen.__next__()
    >>>ok

            这样才能打印出ok来。那除了__next__()方法,我们知道还有两种方法可以执行生成器函数:

    deffoo():print('ok')yieldprint('ok2')yield6#yield也可以返回内容,返回的内容给了调用他的那一步,相当于returngen=foo()next(gen)s=gen.__next__()print(s)#next()#只有两个yield,再执行这一步就会报错了>>>ok>>>ok2>>>6
    next()
    deffoo():print('ok')s=yield6print(s)print('ok2')yieldgen=foo()print(next(gen))gen.send('创给yield的值')#send也可以执行一次生成器,还可以传值给yield>>>ok>>>6>>>创给yield的值>>>ok2
    send()
    简单的生产者消费者模型

           为什么说yield是协程的关键字呢?因为协程是用户态的切换,就是说用户想什么时候切换就什么时候切换(这里的用户就是编程者),而yield刚好可以控制这一点。

    协程的两个优点:

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

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

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

            这里看不懂上面两个优点没关系,看下面的例子就能更好的理解了:

    1.yield方式简单实现协程

            这里将吃包子的人增加一个,看看yield怎么实现:

    import time
    
    def customer(name):
        print('等包子。。。')
        while True:
            baozi = yield
            print('%s拿到了包子%s'%(name,baozi))
    
    def producer(c1,c2):
        c1.__next__()
        c2.__next__()
        n = 0
        while True:
            time.sleep(1)   #做包子需要一点时间
            c1.send(n)
            c2.send(n+1)
            n += 2
    
    if __name__ == '__main__':
        c1 = customer('xiao')
        c2 = customer('bai')
        producer(c1,c2)
    View Code

    2.Greenlet方式

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

    from greenlet import greenlet
    
    def test1():
        print(1111)
        gr2.switch()
        print(2222)
        gr2.switch()
    
    
    def test2():
        print(3333)
        gr1.switch()
        print(4444)
    
    
    gr1 = greenlet(test1)
    gr2 = greenlet(test2)
    gr1.switch()
    View Code

            没有安装这个库的话,需要安装一下,然后看打印的结果,是不是可以控制随时切换啦,很神奇。

    1111
    3333
    2222
    4444

    3.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))
    
    # f('https://www.python.org/')
    # f('https://www.baidu.com/')
    # f('https://www.sina.com.cn/')
    # f("http://www.xiaohuar.com/hua/")
    
    gevent.joinall([
            gevent.spawn(f, 'https://www.python.org/'),
            gevent.spawn(f, 'https://www.baidu.com/'),
            gevent.spawn(f, 'https://www.sina.com.cn/'),
            gevent.spawn(f, 'http://www.xiaohuar.com/hua/'),
    ])
    
    
    print("cost time:",time.time()-start)
    View Code

          大家可以比较一下使用协程和直接按顺序执行有没有提升效率。

          到了这里,协程的基础知识也说完了,还有很多专门开发关于协程的库,因为协程很有作用,这里的例子很简单,但是这里面门道很深的。进程和线程的内容,都是死的,但是协程可以灵活运用,需要不断的去研究创新的。

  • 相关阅读:
    三、Antd react 组件调用ref的用法获取实例
    三、gitextension 报错无法检出版本库的时候
    二、安装引入 antd
    一、React项目骨架搭建
    一、JAVA基础知识
    五、Maven创建Spring(IDEA2019-3-3)
    python爬取快手ios端首页热门视频
    接口测试之基础篇--http协议
    一些测试面试题
    性能测试一些相关的概念
  • 原文地址:https://www.cnblogs.com/pengfy/p/10742248.html
Copyright © 2011-2022 走看看