美文网首页Python全栈
36.Python并发编程之协程

36.Python并发编程之协程

作者: 免跪姓黄 | 来源:发表于2020-04-30 10:03 被阅读0次

    Python并发编程之协程

    1. 协程

      • 协程是程序级别的概念,操作系统根本就没有协程的概念!!!
      • 协程的本质就是一条线程,可以实现多个任务在一条线程上来回切换。协程可以规避I/O操作对程序执行效率的影响,也就是说当CPU调用线程执行任务,遇到I/O或阻塞时,保存这个任务的执行状态,然后让这条线程切换到其他任务上执行,使线程的利用率最大化。
      • 协程对任务的切换是基于用户级的,因此能够感知到的I/O操作(例如socket、网页请求等)是用户级别的,而线程的任务是系统级的,因此线程能够感知的I/O操作(例如文件操作等)更为细腻。
      • 使用协程可以减轻操作系统的负担。
      • 使用协程可以为程序多争取一些CPU的时间片进行任务处理,提高程序执行效率。

    1. 单线程下实现并发

      • 并发指的是多个任务看起来是同时运行的。
      • 并发实现的本质是:切换 + 保存状态。
      • 协程遇到I/O效率才高,纯计算时因为有任务的切换,所以效率反而相比串行效率低。
      • 协程主要用来提升单线程下的线程效率。

    1. 能够让线程在任务间切换并规避I/O的两个模块

      • gevent模块:利用C语言写的greenlet底层模块完成的切换,并实现了自动规避I/O的功能。
      • asyncio模块:利用Python中yield底层语法完成的切换,并实现了自动规避I/O的功能,asyncio模块是基于python原生的协程概念,asyncio模块出现在Python 3.4中,在Python 3.5中,专门为协程提供了两个内置关键字:aysncawaityield fromsend的出现,其实就是为了更好的实现协程。

    1. 协程的gevent模块用法示例

      • gevent模块是第三方模块,需要单独安装才可使用,可以写协程版的并发Socket Server端

        import gevent
        from gevent import monkey  # 需要在导入time之前导入,并执行monkey.patch_all()
        monkey.patch_all()  # 通过monkey.patch_all(),让gevent识别支持的阻塞
        import time
        
        def func():  # 带有I/O操作的任务写在函数中
            print('Start func!')
            time.sleep(1)  # 又遇到阻塞,会切换任务,阻塞完毕,继续执行
            print('Stop func!')
        
        g_1 = gevent.spawn(func)  # 提交func给gevent
        g_2 = gevent.spawn(func)  # 提交func给gevent
        g_3 = gevent.spawn(func)  # 提交func给gevent
        gevent.joinall([g_1, g_2, g_3])  # 主线程阻塞,会切换到协程任务,执行func,直到所有协程任务都完成后才取消阻塞
        
        # 检测gevent对指定模块是否生效的方法:
        # 在monkey.patch_all()之前和之后分别打印一下模块,看结果是否一致,如果结果不一致,说明gevent生效,如果不一致,说明不生效。
        

    1. 协程的asyncio模块用法示例

      • asyncio模块是Python原生的协程模块,不需要单独安装即可使用。

        import asyncio
        
        async def func(name):  # 随便定义一个函数,前面加上async关键字,这个函数就会变成async函数
            print(F'{name} is Start!')
            # await 后面总是跟着会阻塞或有可能阻塞的方法,且await必须写在async函数中
            await asyncio.sleep(1)
            print(F'{name} is Stop!')
        
        loop = asyncio.get_event_loop()
        # loop.run_until_complete(func('asyncio'))  # 开启一个任务
        loop.run_until_complete(asyncio.wait([func('asyncio_1'), func('asyncio_2')]))  # 开启多个任务(异步)
        

    相关文章

      网友评论

        本文标题:36.Python并发编程之协程

        本文链接:https://www.haomeiwen.com/subject/qjaawhtx.html