python的异步编程

      这里的异步编程基于python3.4和python3.5

1、一些重要的概念理解

(1)循环消息队列:

          

  • 异步IO采用消息循环的模式,重复“读取消息—处理消息”的过程
  • 消息模型解决等待IO操作的问题: 
    • 程序发出IO请求,直接结束本轮消息处理,进入下一轮消息的处理
    • 当IO操作完成守,将收到一条IO完成的消息,处理该消息时获取IO操作的结果
    • 在IO操作的这段时间里,异步模型可以循环处理其他操作,而且没有线程切换的消耗,同时处理多个IO请求,适用于大多数IO密集型的应用程序
  • 总结; "异步IO模型"需要一个消息循环,在消息循环中,主线程不断地重复“读取消息-处理消息”这一过程。
  • (2)协程——coroutine
  • 协程,又称微线程,纤程。英文名Coroutine。协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用。子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。
  •        协程调用与函数调用的区别:
  •        协程调用:但执行过程中,在子程序(即函数)内部可中断,然后转而执行别的子程序(另一个函数),在适当的时候再返回                          来接着执行。
                           协程针对的是一个线程中的函数调用之间,所以没有线程切换,是在一个线程中轮流执行和终端多个函数而已,所                          以效率较高,而且不需要锁机制(只有一个线程执行)
                           需要注意的是,子程序内部中断的不是函数调用,而是被调用函数中断(一般来说可能是一条执行命令需要很长时                          间等待结果返回,比如常见的IO操作),转而去执行另一个函数(不是调用另一个函数),类似两个函数轮流执                            行,没有发生函数调用。
  •        函数调用:程序执行中,函数调用是通过函数栈实现,因为栈FILO的特点,通常函数调用过程都是:A调用B,B在执行过程中                        又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。子程序(函数)调用总是一个入口,一次返                              回,调用顺序是明确的。而协程的调用和子程序不同
  • 总结:协程的本质就是一个子程序,即一个使用async关键字定义的函数(在python3.4中使用的是@async.corontine修饰的函                数),它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用
  • (3)、事件循环
  •       python异步IO的核心就在于事件循环,事件循环是一个无限的循环,程序开启一个无限的循环,程序员会把一些协程函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。即协程函数不是自己调用的,而是通过“事件循环”去掉用的。
  •       操作如下:
  •       loop = asyncio.get_event_loop() #获取“事件循环”对象
  • loop.run_until_complete(hello()) #通过事件循环,去调用协程函数
  • loop.close()
  • (4)、任务task
  • 协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含任务的各种状态。即多个coroutine函数可以封装成一组Task然后并发执行,所谓task对象是Future类的子类。保存了协程运行后的状态,用于未来获取协程的结果。任务一般是有多个协程函数的时候,将他们绑定到一个任务组上,可以如下操作:
  • loop = asyncio.get_event_loop()
    tasks = [hello(), hello1(),hello2(),hello3()]  #多个协程函数绑定到一个任务上面,记住多个任务需要将任务写成                                                      列表的形式     
    loop.run_until_complete(asyncio.wait(tasks))         #当任务是列表的时候,必须使用asyncio.wait(t)的形式才行
    loop.close()
    实际上即使没有使用任务task,当传入一个协程,其内部会自动封装成task,如下:
  • loop.run_until_complete(hello()) #程序也会自动将hello封装成一个task任务,若函数有参数,一定要传入参数哦
  • 下面是几种创建任务的方法:
  • 方法1:通过loop.create_task()创建任务
  • t =[loop.create_task(number_sub( 10))] #因为是列表的形式,所以下面必须要用asyncio.wait(t)作为参数,否则会报错
    loop.run_until_complete(asyncio.wait(t))
  • loop.close()
  • 与下面的等价
  • t =loop.create_task(number_sub( 10)) #因为不是列表的形式,所以不需要 asyncio.wait,而直接将t作为参数,否则会报错
    loop.run_until_complete(t)
    loop.close()
    方法2:通过 asyncio.ensure_future()创建任务
  • t =[asyncio.ensure_future(number_sub( 10))] #因为是列表的形式,所以下面必须要用asyncio.wait(t)作为参数,否则会报错
    loop.run_until_complete(asyncio.wait(t))
    loop.close()
    与下面等价
  • t =asyncio.ensure_future(number_sub( 10)) #因为不是列表的形式,所以不需要 asyncio.wait,而直接将t作为参数,否则会报错
    loop.run_until_complete(t)
    loop.close()
    方法3:一次将多个协程函数绑定到同一个任务——要写成任务列表的形式
  • #t=[asyncio.ensure_future(number_sub(10)),asyncio.ensure_future(character_list())] #方法一
    #t =[loop.create_task(number_sub( 10)),loop.create_task(character_list())] #方法二
    t =[number_sub( 10),character_list()] #方法三,这三种方法都可以
    loop.run_until_complete(asyncio.wait(t)) #但因为是列表形式,所以要用wait
    loop.close()
    与下面是等价的
  • t =asyncio.gather(asyncio.ensure_future(number_sub( 5)), asyncio.ensure_future(character_list()))
    print(t)
    loop.run_until_complete(t) #通过asyncio的gather()方法将多个协程函数连接起来,而没有写成列表形式,故而不需要wait()
    print(t)
    loop.close()

  • task进一步了解:
  • task也是一个对象,我们还可以通过打印task,来来查看相关的一些状态信息,如下所示:
  • loop =asyncio.get_event_loop()
    t =loop.create_task(number_sub( 10))
    print(t) #执行之前的状态
    loop.run_until_complete(t)
    print(t)
    loop.close()
    打印结果如下 :
  • <Task pending coro=<number_sub() running at f:\�о������꼶��\Tensorflow���ѧϰ\TensorFlowBoardʵ��\asyncio_3.4.py:3>>
    it's 10
    it's 9
    it's 8
    it's 7
    it's 6
    it's 5
    it's 4
    it's 3
    it's 2
    it's 1
    <Task finished coro=<number_sub() done, defined at f:\�о������꼶��\Tensorflow���ѧϰ\TensorFlowBoardʵ��\asyncio_3.4.py:3> result=None>
    第一个表示执行之前的状态,然后执行出结果,第二个表示执行之后的状态。乱码是因为文件路径中出现了中文的缘故。
  • task是Future的子类。isinstance(task, asyncio.Future)将会输出True。
  • 下面是整个程序的代码:
  • import asyncio

    @asyncio.coroutine #在python3.5里面,改为了async def number_sub(n):
    def number_sub(n):
    while n > 0:
    print( "it's {0} ".format(n))
    yield from asyncio.sleep( 1) #asyncio.sleep()本身就是一个“异步协程函数” 当然这里可以是其他自定义的异步协程函数,
    #这里仅仅是模拟一个耗时的异步过程
    n -= 1 #在python3.5里面,改为了await asyncio.sleep(1)

    @asyncio.coroutine #在python3.5里面,改为了async def number_sub(n):
    def character_list():
    li =[ 'a', 'b', 'c', 'd', 'e', 'f', 'g']
    for i in li:
    print( "it's {0} ".format(i))
    yield from asyncio.sleep( 1) #在python3.5里面,改为了await asyncio.sleep(1)

    loop =asyncio.get_event_loop()
    t =asyncio.gather(asyncio.ensure_future(number_sub( 5)), asyncio.ensure_future(character_list()))
    loop.run_until_complete(t)
    loop.close()

    在python3.5版本中,在语法层面在3.4的基础之上做了一些改进,即所谓的async——await语法。详情可以自己查阅相关的资料。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值