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秒
  • 相关阅读:
    pagefile.sys
    Oracle数据库同义词
    oracle临时表
    修改Oracle并行度
    Oracle 反键索引/反向索引
    Ajax基础2
    DOM高级
    面向对象--高级
    面向对象---中级
    面向对象-初级
  • 原文地址:https://www.cnblogs.com/allenzhang-920/p/10433445.html
Copyright © 2011-2022 走看看