zoukankan      html  css  js  c++  java
  • 协程

    协程(Coroutine),又称微线程,纤程。协程是一种用户态的轻量级线程。

    协程拥有自己的寄存器上下文和栈,协程调度切换时,将寄存器上下文和栈保存到其它地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:

    协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上次调用的状态,换种说法:进入上次离开时所处逻辑流的位置。

    协程的优点:

    无需线程上下文切换的开销(因为是单线程)

    无需原子操作(不会被线程调度机制打断的操作,如修改一个变量)锁定及同步的开销

    方便切换控制流,简化编程模型

    高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题,所以很适用于高并发处理。

    缺点:

    无法利用多核资源:协程的本质是单线程,它不能同时将单个CPU的多个核用上,协程需要和进程配合才能运行在多CPU上,当然我们日常所编写的绝大部分应用都没有这个必要,除非是CPU密集型应用。

    进行阻塞操作会阻塞掉整个程序。

    消费者模型模拟协程

    # coding=utf-8
    
    
    def producer():
        c1.next()  # py3用__next__方法
        c2.next()
        n = 1
        while n < 6:
            print 'producer is making food {}'.format(n)
            c1.send(n)  # send表示唤醒生成器的同时发送一个值
            c2.send(n)
            n += 1
    
    
    def consumer(name):
        print 'Start eating'
        while True:
            food = yield  # 遇到yield的时候停止,被唤醒的时候传值给food
            print '{} eating {}'.format(name, food)
    
    
    c1 = consumer('c1')
    c2 = consumer('c2')
    p = producer()
    
    结果:
    Start eating
    Start eating
    producer is making food 1
    c1 eating 1
    c2 eating 1
    producer is making food 2
    c1 eating 2
    c2 eating 2
    producer is making food 3
    c1 eating 3
    c2 eating 3
    producer is making food 4
    c1 eating 4
    c2 eating 4
    producer is making food 5
    c1 eating 5
    c2 eating 5

    Nginx就是利用的协程实现的高并发,它默认是单线程,遇到IO操作时就切走执行其它CPU操作,IO操作完毕时再切回。

    greenlet实现简单协程中的切换

    # coding=utf-8
    from greenlet import greenlet
    
    
    def f1():
        print 12
        gb.switch()
        print 56
    
    
    def f2():
        print 34
        ga.switch()
        print 78
    
    
    ga = greenlet(f1)
    gb = greenlet(f2)
    ga.switch()
    
    结果:
    12
    34
    56

    模拟协程中的切换

    # coding=utf-8
    import gevent
    
    
    def f1():
        print 12
        gevent.sleep(2)
        print 1112
    
    
    def f2():
        print 34
        gevent.sleep(1)
        print 78
    
    def f3():
        print 56
        gevent.sleep(1)
        print 910
    
    
    gevent.joinall([
        gevent.spawn(f1),
        gevent.spawn(f2),
        gevent.spawn(f3),
    ])
    
    输出:
    12
    34
    56
    78
    910
    1112

    模拟实际应用

    在本地用一个Django的视图函数模拟实际IO处理
    
    urls.py
    
    from django.conf.urls import include, url
    from django.contrib import admin
    from main.views import *
    
    urlpatterns = [
        url(r'^admin/', include(admin.site.urls)),
        url(r'^mysleep/(?P<second>d+)/', mysleep, name='mysleep'),
    ]
    
    views.py
    
    from django.http import JsonResponse
    import time
    
    # Create your views here.
    
    def mysleep(request, second):
        time.sleep(int(second))
        return JsonResponse({'status': 'ok'})
    # 常规的串行效果
    
    # coding=utf-8
    import gevent
    import requests
    import time
    
    
    def f(second):
        r = requests.get('http://127.0.0.1:8000/mysleep/{}/'.format(second))
    
    
    if __name__ == "__main__":
        time_start = time.time()
        f(1)
        f(2)
        print u'串行总计:{}秒'.format(time.time() - time_start)
    
    
    输出:
    串行总计:3.09899997711秒
    
    # 用协程实现并行
    
    # coding=utf-8
    import gevent
    import requests
    import time
    from gevent import monkey
    
    monkey.patch_all()  # 把当前程序的IO操作做标记
    
    
    def f(second):
        r = requests.get('http://127.0.0.1:8000/mysleep/{}/'.format(second))
    
    
    if __name__ == "__main__":
        time_start = time.time()
        gevent.joinall([
            gevent.spawn(f, 1),
            gevent.spawn(f, 2)
        ])
        print u'并行总计:{}秒'.format(time.time() - time_start)
    
    输出:
    并行总计:2.03000020981秒
  • 相关阅读:
    倍福TwinCAT(贝福Beckhoff)基础教程 松下伺服驱动器报错 88怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下伺服驱动器报错 81.0怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下伺服驱动器报错 40怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下伺服驱动器报错 24.0怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下伺服驱动器报错 21.0怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下驱动器试运行提示过速度保护怎么办
    倍福TwinCAT(贝福Beckhoff)基础教程 松下驱动器如何执行绝对值清零
    倍福TwinCAT(贝福Beckhoff)基础教程 松下绝对值驱动器如何做初始化设置
    倍福TwinCAT(贝福Beckhoff)基础教程 松下官方软件开启报错伺服未就绪怎么办
    JAVA Eclipse 启动 Eclipse 弹出“Failed to load the JNI shared library jvm_dll”怎么办
  • 原文地址:https://www.cnblogs.com/allenzhang-920/p/10433445.html
Copyright © 2011-2022 走看看