• python之协程


    协程又叫做微线程,协程是一种用户态的轻量级的线程,协程拥有自己的的寄存器的上下文和栈,协程调度切换时,将寄存器上下文和栈保存
    到其他地方,在切换回来后,恢复之前保存的寄存器的上下文关系,因此协程能保留上一次调用的状态,每次过程重入的时候,就相当于
    进入上一次调用的状态

    协程一定在单线程中,协程的切换是在线程中切换,和单个线程在cpu之间不停的切换是一样的
    但是线程切换是cpu控制的,而协程的切换是用户控制的,操作系统根本无感知;
    协程的切换比线程的切换速度要快,效率要高

    协程的好处
    1、无需线程上下文切换的开销
    2、无需原子操作锁定及同步的开销,因为协程是串行的
    3、方便切换控制流,简化编程模型
    4、高并发,高扩展,低成本,一个cpu支持上万个协程没有问题,所以非常适合高并发处理

    协程的缺点
    1、无法利用多核的优势,但是协程和进程配合就可以使协程运行在不同的cpu上
    2、只要一个协程阻塞(Blocking),就会阻塞整个协程,因为协程是串行的,这个问题必须要解决,才能让协程大范围应用
    解决方法:
    1、如果遇到io操作,则进行协程切换,可以用gevent来实现


    我们来看一段代码
    #Gevent主要是解决协程阻塞的问题,Gevent是一个第三方库,可以轻松通过Gevent实现并发同步
    # 或者异步编程,在gevent中用到的主要模式是Greenlet,他是以C扩展模块形式接入Python的轻量级
    # 协程,Greenlet全部运行在主程序操作系统进程的内部,但是被协作式调度
    import gevent import time def foo(): print("33[41;1mrunning in foo33[0m") gevent.sleep(1) #触发协程切换 # time.sleep(1) print("33[41;1mExplicit context switch to foo aga33[0m") def Bar(): print("33[42;1mExplicit context to bar33[0m") gevent.sleep(2) #触发协程切换 # time.sleep(2) print("33[42;1mImplicit context switch back to bar33[0m") def Car(): print("33[43;1mExplicit context to bar33[0m") gevent.sleep(3) #触发协程切换 # time.sleep(3) print("33[43;1mImplicit context switch back to bar33[0m") gevent.joinall( [gevent.spawn(foo), gevent.spawn(Bar), gevent.spawn(Car) ] ) # 1、running in foo # 2、Explicit context to bar # 3、Explicit context to bar # 4、Explicit context switch to foo aga # 5、Implicit context switch back to bar # 6、Implicit context switch back to bar #先同时打印1,然后遇到gevent,就会进行协程切换,切换到协程2,打印2,然后遇到gevent,又会进行协程切换,打印3,又遇到gevent,再次进行协程切换 #切换到协程1,这个时候就算



    使用urllib+gevent实现多协程的网页爬虫

    from gevent import monkey; monkey.patch_all()
    import gevent
    import urllib.request
    
    #可以简单的爬网页的一个模块
    
    def f(url):
        print("GET:[%s]" %(url))
        resp = urllib.request.urlopen(url)
        data = resp.read()
        print("[%d] bytes received from %s" %(len(data),url))
    
    gevent.joinall(
        [gevent.spawn(f,"http://www.baidu.com/"),
         gevent.spawn(f,"http://www.python.org/"),
         gevent.spawn(f,"http://www.sina.com/"),
         gevent.spawn(f,"http://www.163.com/"),
        ]
    )
    

      

    结果如下,遇到阻塞就会自动跳转到其他的协程,这个阻塞gevent会自动判断的

    GET:[http://www.baidu.com/]
    GET:[http://www.python.org/]
    GET:[http://www.sina.com/]
    GET:[http://www.163.com/]
    [111488] bytes received from http://www.baidu.com/
    [601132] bytes received from http://www.sina.com/
    [660092] bytes received from http://www.163.com/
    [48713] bytes received from http://www.python.org/
    

      

  • 相关阅读:
    LINQ Practice
    windows下python环境安装
    kafka安装教程
    使用python连接mysql/oracle
    使用百度地图实现地图网格
    单链表反转java代码
    mysql的索引问题分析
    java中String字符串的==解析
    辗转相除法的原理
    myeclipse2014新建maven项目
  • 原文地址:https://www.cnblogs.com/bainianminguo/p/7430017.html
Copyright © 2020-2023  润新知