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

    协程:是单线程下的并发,又称微线程。

    什么是线程?:

    协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。

    协程的本质

    协程的本质就是在单线程下,由用户自己控制一个任务遇到io阻塞了就切换另外一个任务去执行,以此来提升效率

    对于不涉及io的操作,单纯的切换反而会降低效率

    #并发执行
    import time
    
    
    def producer():
        g = consumer()
        next(g)
        for i in range(10000000):
            g.send(i)
    
    
    def consumer():
        while True:
            res = yield
    
    
    start_time = time.time()
    producer()
    stop_time = time.time()
    print(stop_time-start_time)
    
    
    
    #串行
    import time
    
    def producer():
        res=[]
        for i in range(10000000):
            res.append(i)
        return res
    
    
    def consumer(res):
        pass
    
    
    start_time=time.time()
    res=producer()
    consumer(res)
    stop_time=time.time()
    print(stop_time-start_time)
    

    总结协程的优缺点:

    优点

    1、协程开销小,属于程序级别的切换,操作系统感知不到

    2、单线程下可以实现并发效果, 最大限度地利用CPU

    缺点

    1、协程的本质是单线程下,无法利用多核优势。

    2、协程是指单线程,一旦协程出现阻塞,将会阻塞整个线程。

    协程的特点:

    1、必须在一个单线程里实现并发

    2、修改共享数据不加锁

    3、用户程序自己控制保存上下文

    4、一个协程遇到io操作自动切换到其他协程。

    grennlet模块

    并不能监听(不能遇到io自动切换)

    from greenlet import greenlet
    
    
    def func1():
        print('123')
        g2.switch()
        print('456')
    
    
    def func2():
        print('abc')
        g1.switch()
        print('qqq')
        g1.switch()
    
    
    if __name__ == '__main__':
        g1 = greenlet(func1)
        g2 = greenlet(func2)
        g1.switch()
    

    gevent模块

    #用法
    g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的
    
    g2=gevent.spawn(func2)
    
    g1.join() #等待g1结束
    
    g2.join() #等待g2结束
    
    #或者上述两步合作一步:gevent.joinall([g1,g2])
    
    g1.value#拿到func1的返回值
    

    遇到io自动切换

    import gevent
    def eat(name):
        print('%s eat 1' %name)
        gevent.sleep(2)
        print('%s eat 2' %name)
    
    def play(name):
        print('%s play 1' %name)
        gevent.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])
    print('主')
    
    同步与异步的性能比较
    import gevent
    import time
    
    
    def task(i):
        gevent.sleep(1)
        
        print(i)
        
        # res = 0
        # for i in range(1000):
        #     res = i**i
        # return res
    
    
    def async():
        threads = [gevent.spawn(task, i) for i in range(10)]
        gevent.joinall(threads)
        
        
    def sync():
        for i in range(10):
            gevent.spawn(task, i)
     
            
    t1 = time.time()
    sync()
    t2 = time.time()
    async()
    t3 = time.time()
    print('sync run time', t2 - t1)
    print('asyn run time', t3 - t2)
    
    协程实现FTP

    服务端

    from gevent import monkey;monkey.patch_all()
    import socket
    import gevent
    
    def read(conn):
        try:
            while True:
                data = conn.recv(1024).decode()
                if not data:
                    break
                conn.send(data.upper().encode())
        except Exception as e:
            print(e)
            conn.close()
    
    
    if __name__ == '__main__':
        server = socket.socket()
        server.bind(('127.0.0.1', 9999))
        server.listen(10)
        while True:
            conn, addr = server.accept()
            gevent.spawn(read, conn)
    

    客户端

    import socket
    
    client = socket.socket()
    client.connect(('127.0.0.1', 9999))
    while True:
        msg = input('>>').strip()
        if not msg: continue
        client.send(msg.encode())
        data = client.recv(1024).decode()
        print(data)
    

    协程实现生产者消费者模型

    import queue
    import gevent
    
    
    def comsumer():
        print("消费者")
        while True:
            gevent.sleep(0.1)
            res = q.get()
            # print('res', res)
            if not res:
                break
            print('消耗了', res)
    
    
    def producer(n):
        print("生产者")
        for i in range(1, 10):
            q.put(i)
            print('%s生产了%s' % (n, i))
    
    
    if __name__ == '__main__':
        q = queue.Queue()
        p1 = gevent.spawn(producer, 'p1')
        p2 = gevent.spawn(producer, 'p2')
        p3 = gevent.spawn(producer, 'p3')
        c1 = gevent.spawn(comsumer)
    
        p1.join()
        p2.join()
        p3.join()
     
        q.put(0)
        c1.join()
        print('zhu')
    
  • 相关阅读:
    【Henu ACM Round#20 B】Contest
    【Henu ACM Round#20 A】 Fancy Fence
    【Henu ACM Round#19 F】Dispute
    【Henu ACM Round#19 E】 Om Nom and Candies
    【Henu ACM Round#19 D】 Points on Line
    【Henu ACM Round#19 C】 Developing Skills
    【Henu ACM Round#19 B】 Luxurious Houses
    【Henu ACM Round#19 A】 Vasya the Hipster
    【Codeforces Round #460 (Div. 2) D】Substring
    JQuery中attr ,html,text,val,的一些用法
  • 原文地址:https://www.cnblogs.com/Jason-lin/p/8545251.html
Copyright © 2011-2022 走看看