• 并发编程之 协程


    协程 (单线程下实现并发)

      进程:资源单位

      线程:执行单位

      协程:单线程下实现并发

    并发:切换+保存状态

    程序员自己通过代码自己检测程序中的IO

    一旦遇到了IO自己通过代码切换

    给操作系统的感觉就是你这个线程没有任何的IO    从而提升代码的运行效率

    切换+保存状态一定能够提升效率吗?

      1.当任务是IO密集型的情况下     提升效率

         2.当任务是计算密集型的情况下    降低效率

    接下来 我们进行验证  

    1.在计算密集型的情况下,通过切换+保存状态   效率到底是降低了还是提升了呢?

    这是串行执行的时间:

    # 串行执行 0.8540799617767334
    import time
    
    def func1():
        for i in range(10000000):
            i+1
    
    def func2():
        for i in range(10000000):
            i+1
    
    start = time.time()
    func1()
    func2()
    stop = time.time()
    print(stop - start)

    下面是切换+保存状态的执行时间:

    #基于yield并发执行  1.3952205181121826
    import time
    def func1():
        while True:
            10000000+1
            yield
    
    def func2():
        g=func1()
        for i in range(10000000):
            time.sleep(100)  # 模拟IO,yield并不会捕捉到并自动切换
            i+1
            next(g)
    
    start=time.time()
    func2()
    stop=time.time()
    print(stop-start)

    根据执行时间来看  明显效率是降低了

    2.在IO密集型的情况下,通过切换+保存状态   效率到底是降低了还是提升了呢?

    首先我们需要找到一个能够识别IO的工具,遇到IO就可以自动的切换

    这里我们就用到了gevent模块

    这是串行的执行结果:

    from gevent import monkey;monkey.patch_all()
    from gevent import spawn
    import  time
    
    '''
    注意  gevent模块没办法自动识别 time.sleep 等io情况
    需要你手动配置一个参数
    '''
    
    def heng():
        print('哼!')
        time.sleep(2)
        print('哼!')
    
    def ha():
        print('哈!')
        time.sleep(3)
        print('哈!')
    
    start = time.time()
    
    heng()
    ha()
    
    print(time.time()-start)
    #5.041796445846558

    下面是通过切换+保存状态来执行  利用gevent模块

    from gevent import monkey;monkey.patch_all()
    from gevent import spawn
    import  time
    
    '''
    注意  gevent模块没办法自动识别 time.sleep 等io情况
    需要你手动配置一个参数
    '''
    
    def heng():
        print('哼!')
        time.sleep(2)
        print('哼!')
    
    def ha():
        print('哈!')
        time.sleep(3)
        print('哈!')
    
    start = time.time()
    
    g= spawn(heng)
    g1 = spawn(ha)
    g.join()
    g1.join()
    
    print(time.time()-start)
    
    #3.041301727294922

    明显的看出在IO密集型的情况下  切换+保存状态能够提升效率

    Gevent应用举例 

    利用协程实现并发

    实现TCP服务端的并发

    server端

    import socket
    from gevent import monkey;monkey.patch_all()
    from gevent import spawn
    
    sk = socket.socket()
    sk.bind(('127.0.0.1', 8080))
    sk.listen()
    def talk(conn):
        while True:
            try:
                data = conn.recv(1024)
                if len(data) == 0 :break
                print(data.decode('utf-8'))
                conn.send(b'hi')
            except ConnectionResetError as e:
                print(e)
                break
        conn.close()
    
    def server():
        while True:
            conn,addr = sk.accept()
            spawn(talk,conn)
    
    if __name__ == '__main__':
        res = spawn(server)
        res.join()

    client端 起了400个线程

    from threading import Thread
    import socket
    
    def client():
        sk = socket.socket()
        sk.connect(('127.0.0.1',8080))
    
    
        while True:
            sk.send(b'hello')
            data = sk.recv(1024).decode('utf-8')
            print(data)
    
    for i in range(400):
        t = Thread(target=client)
        t.start()
    万般皆下品,唯有读书高!
  • 相关阅读:
    Redis5.x五种数据类型常见命令
    Redis5.x安装以及常见数据类型
    《Redis5.x入门教程》正式推出
    PPT制作套路指南
    如何更优雅地对接第三方API
    软件开发要质量还是要效率?
    前后端分离对于开发人员的挑战
    Spring中老生常谈的FactoryBean
    消费端如何保证消息队列MQ的有序消费
    《ElasticSearch6.x实战教程》之实战ELK日志分析系统、多数据源同步
  • 原文地址:https://www.cnblogs.com/s686zhou/p/11363057.html
Copyright © 2020-2023  润新知