zoukankan      html  css  js  c++  java
  • python生成器和使用gevent操作协程

    python中的生成器是一种特殊的迭代器,可以类比成类:

    如下定义斐波那契数列,初始化obj1,相当于new 出一个对象

    以下两种方式输出结果相同,均为斐波那契数列前10项

    def fibonacci(all_num):
        a, b = 0, 1
        current_num = 0
        while current_num < all_num:
            yield a
            a, b = b, a + b
            current_num += 1
    obj1 = fibonacci(10)
    for ind in range(10):
        print(next(obj1))
    def fibonacci(all_num):
        a, b = 0, 1
        current_num = 0
        while current_num < all_num:
            yield a
            a, b = b, a + b
            current_num += 1
    obj1 = fibonacci(10)
    for obj in obj1:
        print(obj)

    其中yield关键字说明此函数为一个生成器,yield a可以作为一个返回值打断函数并返回结果,此为协程的雏形,如果定义两个生成器实例,两个生成器通过yield可以实现交替运行,即为协程

    看如下代码:

    def fibonacci(all_num,name):
        a, b = 0, 1
        current_num = 0
        while current_num < all_num:
            yield a
            print(name)
            a, b = b, a + b
            current_num += 1
    obj1 = fibonacci(10,"fib1")
    obj2 = fibonacci(10,"fib2")
    for ind in range(10):
        print(next(obj1))
        print(next(obj2))

    输出:

    这便实现了协程交替工作

    使用greenlet管理协程:

    使用greenlet的switch()方法替换yield

    from greenlet import greenlet
    
    def wh2():
        while True:
            print("---2---")
            gr1.switch()
            time.sleep(0.1)
    
    
    def wh1():
        while True:
            print("---1---")
            gr2.switch()
            time.sleep(0.1)
    
    
    gr1 = greenlet(wh1)
    gr2 = greenlet(wh2)
    gr1.switch()

    输出如下:

    使用最多最广泛的还是使用gevent管理协程:

    安装gevent

    pip install gevent

    def wh2():
    while True:
    print("---2---")
    time.sleep(0.1)


    def wh1():
    while True:
    print("---1---")
    time.sleep(0.1)

    def spawn():
    g1 = gevent.spawn(wh1)
    g2 = gevent.spawn(wh2)
    g1.join()
    g2.join()

    spawn()

    直接代码中去掉yield、switch,使用gevent.spawn()方法---下蛋

    但是输出如下:

    原因是我们需要把time.sleep()替换成gevent.sleep(),join也可以替换成joinall

    def wh2():
        while True:
            print("---2---")
            gevent.sleep(0.1)
    
    
    def wh1():
        while True:
            print("---1---")
            gevent.sleep(0.1)
    
    def spawn():
        g1 = gevent.spawn(wh1)
        g2 = gevent.spawn(wh2)
        gevent.joinall([g1,g2])
    
    spawn()

    如果不替换time.sleep(),我们也可以使用gevent的money模块全局替换:

    from gevent import monkey
    
    monkey.patch_all()

    输出如下:

    实现了协程工作,协程的开销是比线程还要小的,以上代码的sleep部分实际中可以去掉,因为在耗时部分gevent才会走其他的实例,为了方便测试才加上的,不然会直接不卡顿的for循环其中一个实例,如下的例子就是没有sleep代码的协程工作例子,由于网络通信比较耗时,所以协程会自动切换到另一个实例,好像是并发工作一样。

    协程demo:

    import gevent
    from gevent import monkey
    import urllib.request
    # 补丁 实现协同工作:看上去就像是多线程 monkey.patch_all() def download_img(name,url): req
    = urllib.request.urlopen(url) img_content = req.read() with open(name,"wb") as f: f.write(img_content) if __name__ == '__main__': gevent.joinall( [ gevent.spawn(download_img,"1.jpg","https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_match%2F0%2F12070081997%2F0.jpg&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1627992970&t=0a1f9c49767613a1f8ec792c975c3ae6"), gevent.spawn(download_img,"2.jpg","https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_match%2F0%2F6311385436%2F0.jpg&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1627992675&t=08d6f5ec50eb7570be0350512a67caea") ] )
  • 相关阅读:
    LeetCode 295. Find Median from Data Stream (堆)
    LeetCode 292. Nim Game(博弈论)
    《JavaScript 模式》读书笔记(4)— 函数2
    《JavaScript 模式》读书笔记(4)— 函数1
    《JavaScript 模式》读书笔记(3)— 字面量和构造函数3
    《JavaScript 模式》读书笔记(3)— 字面量和构造函数2
    《JavaScript 模式》读书笔记(3)— 字面量和构造函数1
    《JavaScript 模式》读书笔记(2)— 基本技巧3
    《JavaScript 模式》读书笔记(2)— 基本技巧2
    《JavaScript 模式》读书笔记(2)— 基本技巧1
  • 原文地址:https://www.cnblogs.com/fengwenzhee/p/14969377.html
Copyright © 2011-2022 走看看