zoukankan      html  css  js  c++  java
  • python之路 -- 协程

      单线程下,我们不可避免程序中出现io操作,但如果我们能在自己的程序中(即用户程序级别,而非操作系统级别)控制单线程下的多个任务能在一个任务遇到io阻塞时就切换到另外一个任务去计算,这样就保证了该线程能够最大限度地处于就绪态,即随时都可以被cpu执行的状态,相当于我们在用户程序级别将自己的io操作最大限度地隐藏起来,从而可以迷惑操作系统,让其看到:该线程好像是一直在计算,io比较少,从而更多的将cpu的执行权限分配给我们的线程。

    1.协程

    --本质上是一个线程

    --能够在多个任务之间切换来节省一些IO时间

    --协程中任务之间的切换也消耗时间,但是开销要远远小于进程线程之间的切换

    2.用yield实现任务的切换

    --yiled可以保存状态,yield的状态保存与操作系统的保存线程状态很像,但是yield是代码级别控制的,更轻量级

    --send可以把一个函数的结果传给另外一个函数,以此实现单线程内程序之间的切换

    import time
    def consumer():
        while True:
            x = yield
            time.sleep(1)
            print('处理了数据 :',x)
    
    def producer():
        c = consumer()
        next(c)
        for i in range(10):
            time.sleep(1)
            print('生产了数据 :',i)
            c.send(i)
    
    producer()

    3.greenlet模块实现协程

    from greenlet import greenlet
    def eat():
        print('eating start')
        g2.switch()           
        # 转换到函数play并保存执行进度,当再转换到此函数时,接着此处执行
        print('eating end')
        g2.switch()
    
    def play():
        print('playing start')
        g1.switch()
        print('playing end')
    
    g1 = greenlet(eat)    
    # 将eat函数交给greenlet执行,赋给g1,当调用g1.switch()时就去执行eat函数
    g2 = greenlet(play)
    g1.switch()   # 执行函数eat
    
    """执行结果为:
    eating start
    playing start
    eating end
    playing end
    """

    4. gevent模块实现协程

    from gevent import monkey;monkey.patch_all()
    # 这句代码的作用就是让协程的这个模块认识其他模块中的IO操作,然后再执行过程中遇到IO操作进行跳转。必须在第一句
    import gevent
    import time
    def eat():
        print('eating start')
        time.sleep(1)
        print('eating end')
    
    def play():
        print("playing start")
        time.sleep(1)
        print('playing end')
    
    g1 = gevent.spawn(eat)
    g2 = gevent.spawn(play)
    g1.join()
    g2.join()
    
    """执行结果为:
    eating start
    playing start
    eating end
    playing end
    """

    # 进程和线程的任务切换由操作系统完成

    # 协程任务之间的切换由程序(代码)完成,只有遇到协程模块能识别的IO操作的时候,程序才会进行任务切换,实现并发的效果

     同步 和 异步
    from gevent import monkey
    monkey.patch_all()
    import time
    import gevent
    
    def task(n):
        time.sleep(0.5)
        print(n)
    
    def sync():
        for i in range(10):
            task(i)
    
    def async():
        g_lst = []
        for i in range(10):
            g = gevent.spawn(task,i)
            g_lst.append(g)
        gevent.joinall(g_lst)  # for g in g_lst:g.join()
    
    sync()  # 同步
    async() # 异步

    协程 : 能够在一个线程中实现并发效果的概念

       能够规避一些任务中的IO操作

       在任务的执行过程中,检测到IO就切换到其他任务

       协程 在一个线程上 提高CPU 的利用率

       协程相比于多线程的优势 切换的效率更快

    # 爬虫的例子
    # 请求过程中的IO等待
    from gevent import monkey;monkey.patch_all()
    import gevent
    from urllib.request import urlopen    # 内置的模块
    def get_url(url):
        response = urlopen(url)
        content = response.read().decode('utf-8')
        return len(content)
    
    g1 = gevent.spawn(get_url,'http://www.baidu.com')
    g2 = gevent.spawn(get_url,'http://www.sogou.com')
    g3 = gevent.spawn(get_url,'http://www.taobao.com')
    g4 = gevent.spawn(get_url,'http://www.hao123.com')
    g5 = gevent.spawn(get_url,'http://www.cnblogs.com')
    gevent.joinall([g1,g2,g3,g4,g5])
    print(g1.value)
    print(g2.value)
    print(g3.value)
    print(g4.value)
    print(g5.value)
    
    # 几乎同时得到输出结果
    爬虫的例子

    5.协程实现socketserver

      server端

    from gevent import monkey
    monkey.patch_all()
    import socket
    import gevent
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',8080))
    sk.listen()
    
    def talk(conn):
        conn.send(b'hello')
        print(conn.recv(1024).decode('utf-8'))
        conn.close()
    
    while True:
        conn,addr = sk.accept()
        gevent.spawn(talk,conn)
    
    sk.close()
     
    View Code

      client端

    import socket
    sk = socket.socket()
    sk.connect(('127.0.0.1',8080))
    
    msg = sk.recv(1024).decode('utf-8')
    print(msg)
    info = input('>>>').encode('utf-8')
    sk.send(info)
    sk.close()
    View Code
  • 相关阅读:
    HDU 5492 Find a path
    codeforce gym 100548H The Problem to Make You Happy
    Topcoder SRM 144 Lottery
    codeforce 165E Compatible Numbers
    codeforce gym 100307H Hack Protection
    区间DP总结
    UESTC 1321 柱爷的恋爱 (区间DP)
    HDU 4283 You Are the One (区间DP)
    HDU 2476 String painter (区间DP)
    UESTC 426 Food Delivery (区间DP)
  • 原文地址:https://www.cnblogs.com/aberwang/p/9466603.html
Copyright © 2011-2022 走看看