zoukankan      html  css  js  c++  java
  • 协程

    协程的初识

    协程本质上就是一个线程 一个线程实现并发.如果协程中处理的所有任务都遇到了阻塞 协程就会停止 只有阻塞完成会切回来 进程间是由操作系统调控cpu 而协程是由我们自己书写的程序调控的

    单个cpu: 10个任务,让你给我并发的执行这个10个任务:

    1. 方式一:开启多进程并发执行, 操作系统切换+保持状态.
    2. 方式二:开启多线程并发执行,操作系统切换+保持状态.
    3. 方式三:开启协程并发的执行, 自己的程序 把控着cpu 在3个任务之间来回切换+保持状态.

    协程他切换速度非常快,蒙蔽操作系统的眼睛,让操作系统认为cpu一直在运行你这一个线程(协程.)

    单核心下处理多任务最好的方式

    协程 开销小. 运行速度快. 协程会长期霸占cpu只执行我程序里面的所有任务.

    并发的本质:就是切换+保持状态.

    协程处理IO密集型, 计算密集型,还是串行好.

    什么是协程? 单个线程并发的处理多个任务. 程序控制协程的切换+保持状态.

    协程的特点:

    1. 必须在只有一个单线程里实现并发
    2. 修改共享数据不需加锁
    3. 用户程序里自己保存多个控制流的上下文栈(保持状态)
    4. 附加:一个协程遇到IO操作自动切换到其它协程

    工作中:

    ​ 一般在工作中我们都是进程+线程+协程的方式来实现并发,以达到最好的并发效果,如果是4核的cpu,一般起5个进程,每个进程中20个线程(5倍cpu数量),每个线程可以起500个协程,大规模爬取页面的时候,等待网络延迟的时间的时候,我们就可以用协程去实现并发。 并发数量 = 5 * 20 * 500 = 50000个并发,这是一般一个4cpu的机器最大的并发数。nginx在负载均衡的时候最大承载量就是5w个

      单线程里的这20个任务的代码通常会既有计算操作又有阻塞操作,我们完全可以在执行任务1时遇到阻塞,就利用阻塞的时间去执行任务2。。。。如此,才能提高效率,这就用到了Gevent模块。

    推导过程

    切换 + 保持状态

    # 切换 + 保持状态
    def gen():
        for i in range(10,1,-1):
            yield i
    
    def func():
        obj = gen()
        for i in range(5):
            print(next(obj))
    func()
    

    利用greenlet 切换 +保持状态

    用greenlet模块可以非常简单地实现这20个任务直接的切换

    真正的协程模块就是使用greenlet完成的切换

    # 切换 +保持状态(遇到IO不会主动切换)
    # switch()代表切换
    from greenlet import greenlet
    import time
    def eat(name):
        print('%s eat 1' %name)  # 2
        g2.switch('taibai')  # 3
        time.sleep(3)
        print('%s eat 2' %name)  # 6
        g2.switch()  # 7
    
    def play(name):
        print('%s play 1' %name)  # 4
        g1.switch()  # 5 切换
        print('%s play 2' %name)  # 8
    
    g1=greenlet(eat)
    g2=greenlet(play)
    

    最终版本

    必须要jion 不然线程结束了
    # g1.join()
    # g2.join()
    gevent.joinall([g1,g2])#与上面2个合并效果相同
    
    
    # 最终版本:
    import gevent## 切换 +保持状态(遇到IO不会主动切换)
    
    from gevent import monkey
    monkey.patch_all()  # 打补丁: 将下面的所有的任务的阻塞都打上标记 遇到就切换
    
    def eat(name):
        print('%s eat 1' %name)
        time.sleep(2)
        print('%s eat 2' %name)
    
    def play(name):
        print('%s play 1' %name)
        time.sleep(1)
        print('%s play 2' %name)
    
    g1 = gevent.spawn(eat,'egon')#固定写法
    g2 = gevent.spawn(play,name='egon')
    
    # g1.join()
    # g2.join()
    gevent.joinall([g1,g2])
    
  • 相关阅读:
    jquery proxy && delegate 的比较
    最近开发问题记录
    调研雅黑字体在各浏览器的显示
    我对浮动的认识(一)
    我对浮动的理解和认识(二)
    跨浏览器事件的其他问题(小记)
    web数据交互方式
    闪光字的处理
    IE hasLayout的问题总结
    文字内容溢出用点点点(...)省略号
  • 原文地址:https://www.cnblogs.com/saoqiang/p/12388509.html
Copyright © 2011-2022 走看看