协程(解决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

原文地址:https://www.cnblogs.com/bigox/p/10610270.html