zoukankan      html  css  js  c++  java
  • 协程(解决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

  • 相关阅读:
    < java.util >-- Set接口
    Codeforces 627 A. XOR Equation (数学)
    Codeforces 161 B. Discounts (贪心)
    Codeforces 161 D. Distance in Tree (树dp)
    HDU 5534 Partial Tree (完全背包变形)
    HDU 5927 Auxiliary Set (dfs)
    Codeforces 27E. Number With The Given Amount Of Divisors (暴力)
    lght oj 1257
    Codeforces 219D. Choosing Capital for Treeland (树dp)
    Codeforces 479E. Riding in a Lift (dp + 前缀和优化)
  • 原文地址:https://www.cnblogs.com/bigox/p/10610270.html
Copyright © 2011-2022 走看看