• 协程(解决python并发问题)


    1.协程概念

    • 能够在一个线程下的多个任务之间来回切换,那么每一个任务就是协程

    进程和线程的切换是由操作系统控制切换

    • 协程和线程
      #共同点:
         -线程和协程的创建,切换销毁都需要时间开销,
         -在cpython中线程和协程都不能利用多个cpu(只能并发)
      #不同点:
         -多线程线程的切换是由操作系统完成,而协程的切换是通过代码实现,操作系统不可见
         -多线程创建,切换销毁时间开销较大,协程的时间开销很小,携程切换用户可操作性,不会增加操作系统压力

    2.协程操作(模块)

    • 线程切换

      • 两种切换方式

        两种切换方式
          # 原生python完成   yield asyncio
          # C语言完成的python模块 greenlet gevent
        • 原生python代码实现 (asyncos 模块)- asyncos利用yield记录线程代码执行状态和位置,但是yield不能规避io操作

        • C语言完成的PYthon模块(#greenlet模块)

    • 规避IO操作,切换原理(了解)

       

    2.1 gevent 第三方模块

    • 基本格式

      import time
      import gevent
      from gevent import monkey
      monkey.patch_all() #用mokey模块使协程识别多次使用的外部方法,比如time.time()
      def eat():
         print('wusir is eating')
         time.sleep(1)
         print('wusir finished eat')

      def sleep():
         print('小马哥 is sleeping')
         time.sleep(1)
         print('小马哥 finished sleep')

      # g1 = gevent.spawn(eat)   # 创造一个协程任务
      # g2 = gevent.spawn(sleep)   # 创造一个协程任务
      # print(g1.value)
      # print(g2.value)
      # # g1.join()   # 阻塞 直到g1任务完成为止
      # # g2.join()   # 阻塞 直到g1任务完成为止
      # gevent.joinall([g1,g2,g3]) #知道列表内的协程任务全部终止为止
      g_l = []
      for i in range(10):
         g = gevent.spawn(eat)
         g_l.append(g)
      gevent.joinall(g_l)
    • 接收返回值

      • value

        # g1 = gevent.spawn(eat)  # 创造一个协程任务
        # g2 = gevent.spawn(sleep) # 创造一个协程任务
        # print(g2.value)

    2.2 asyncio 内置模块(记住启动一个/多个线程)

    • async-异步 sync-同步

    • asyncio 协程基本格式

      #起一个任务

      import asyncio #插入asyncio模块
      async def demo(): #创建async函数
           print('start')
           await asyncio.sleep(1) #阻塞,阻塞必须写入await之后 且使用asyncio模块自己的方法
           print('end')
       loop = asyncio.get_event_loop()   #创建一个第三方事件循环,监测是否IO
       loop.run_until_complete(demo()) #吧demo任务丢到事件循环中去执行
    #起多个任务,且没有返回值

    import asyncio
     
    async def demo():
       print('start')
       await asyncio.sleep(1) #阻塞,阻塞必须写入await之后 且使用asyncio模块自己的方法
       print('end')

    loop = asyncio.get_event_loop()
    wait_obj=asyncio.wait([demo(),demo(),demo()])
    loop.run_until_complete(wait_obj)

     

      #起多个任务,有返回值,可以绑定回调函数
     
    import asyncio
    asrnc def demo():
    print('start')
        await asyncio.sleep(1) #阻塞,阻塞必须写入await之后 且使用asyncio模块自己的方法
        print('end')
        retunrn 123
     
    loop = asyncio.get-event_loop()
    t1 = loop.create_task(demo())
    t2 = loop.create_task(demo())
    tasks=[t1,t2]
    wait_obj=asyncio.wait([t1,t2])
    loop.run_until_complete(wait_obj)
    for i in easks:
    print(tasks.result())

     

    • asyncos是python原生的底层的协程模块

      • 爬虫,webserver框架

      • 爬虫网络编程的效率和并发效果

    • await 阻塞必须写在await之后,告诉协程函数这里要切换出去,还能保证一会再切回来

    • await 必须写在async函数里,async是协程函数

    • loop 时间循环

      • 所有的协程的执行,调度都离不开这个loop

  • 相关阅读:
    编译原理实验(NFA转DFA,LL1文法)
    欧几里得算法
    Codeforces Round #697 (Div. 3) A -D 解题报告
    STM32使用SPI驱动WS2812灯带
    读书笔记---<<人月神话>>5
    基于百度和echars接口,实现多点连接
    读书笔记---<<人月神话>>4
    读书笔记---<<人月神话>>3
    软件杯----------害虫地区分布展示
    web页面采用高德地图JS api和Web api实现路径规划
  • 原文地址:https://www.cnblogs.com/bigox/p/10610270.html
Copyright © 2020-2023  润新知