您的位置:首页 > 编程语言 > Python开发

python的异步编程

2017-12-20 15:28 36 查看
      这里的异步编程基于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语法。详情可以自己查阅相关的资料。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息