zoukankan      html  css  js  c++  java
  • 并发编程之协程

    协程

    协程:是单线程下的并发,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。、

    需要强调的是:

    #1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,切换其他线程运行)
    #2. 单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效率(!!!非io操作的切换与效率无关)
    

    对比操作系统控制线程的切换,用户在单线程内控制协程的切换

    优点如下:

    #1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
    #2. 单线程内就可以实现并发的效果,最大限度地利用cpu
    

    缺点如下:

    #1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
    #2. 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程
    

    总结协程特点:

    1. 必须在只有一个单线程里实现并发
    2. 修改共享数据不需加锁
    3. 用户程序里自己保存多个控制流的上下文栈

    切换是否就一定提升效率

    在进行计算密集型操作时,切换和保存状态并不能提高效率,反而会影响效率

    在进行I/O密集型操作时,切换和保存状态能较明显的提高CPU的利用率

    gevent模块

    安装

    pip3 install gevent
    
    from gevent import monkey;monkey.patch_all()
    import time
    from gevent import spawn
    
    """
    gevent模块本身无法检测常见的一些io操作
    在使用的时候需要你额外的导入一句话
    from gevent import monkey
    monkey.patch_all()
    又由于上面的两句话在使用gevent模块的时候是肯定要导入的
    所以还支持简写
    from gevent import monkey;monkey.patch_all()
    """
    def heng():
        print('哼')
        time.sleep(2)
        print('哼')
    
    
    def ha():
        print('哈')
        time.sleep(3)
        print('哈')
    
    def hei():
        print('嘿嘿嘿')
        time.sleep(5)
        print('嘿嘿嘿')
    
    
    start_time = time.time()
    g1 = spawn(heng)
    g2 = spawn(ha)
    g3 = spawn(hei)
    g1.join()
    g2.join()  # 等待被检测的任务执行完毕 再往后继续执行
    g3.join()
    # heng()
    # ha()
    # print(time.time() - start_time)  # 5.005702018737793
    print(time.time() - start_time)  # 3.004199981689453   5.005439043045044
    '''
    哼
    哈
    嘿嘿嘿
    哼
    哈
    嘿嘿嘿
    5.0232994556427
    '''
    

    协程实现TCP服务端的并发

    # 服务端
    from gevent import monkey;monkey.patch_all()
    import socket
    from gevent import spawn
    
    
    def communication(conn):
        while True:
            try:
                data = conn.recv(1024)
                if len(data) == 0: break
                conn.send(data.upper())
            except ConnectionResetError as e:
                print(e)
                break
        conn.close()
    
    
    def server(ip, port):
        server = socket.socket()
        server.bind((ip, port))
        server.listen(5)
        while True:
            conn, addr = server.accept()
            spawn(communication, conn)
    
    
    if __name__ == '__main__':
        g1 = spawn(server, '127.0.0.1', 8080)
        g1.join()
    
        
    # 客户端
    from threading import Thread, current_thread
    import socket
    
    
    def x_client():
        client = socket.socket()
        client.connect(('127.0.0.1',8080))
        n = 0
        while True:
            msg = '%s say hello %s'%(current_thread().name,n)
            n += 1
            client.send(msg.encode('utf-8'))
            data = client.recv(1024)
            print(data.decode('utf-8'))
    
    
    if __name__ == '__main__':
        for i in range(500):
            t = Thread(target=x_client)
            t.start()
    

    总结

    """
    理想状态:
    	我们可以通过
    	多进程下面开设多线程
    	多线程下面再开设协程序
    	从而使我们的程序执行效率提升
    """
    
  • 相关阅读:
    Python 之pymysql数据库模块
    Python 之sqlite3数据库模块
    Python 之操作sqlite3
    Python 之requests网络请求模块
    Python 之os文件目录模块
    Python 之json模块
    Python 之random随机数模块
    vue.js三种安装方式
    VUE学习之计算属性computed
    vue添加背景音乐
  • 原文地址:https://www.cnblogs.com/Henry121/p/12708727.html
Copyright © 2011-2022 走看看