Python async/await 手册

编辑:光环大数据 来源: 互联网 时间: 2017-10-31 14:29 阅读:

  Pythonasync/await手册,在过去几年内,异步编程由于某些好的原因得到了充分的重视。虽然它比线性编程难一点,但是效率相对来说也是更高。

比如,利用Python的异步协程(asynccoroutine),在提交HTTP请求后,就没必要等待请求完成再进一步操作,而是可以一边等着请求完成,一边做着其他工作。这可能在逻辑上需要多些思考来保证程序正确运行,但是好处是可以利用更少的资源做更多的事。

即便逻辑上需要多些思考,但实际上在Python语言中,异步编程的语法和执行并不难。跟Javascript不一样,现在Python的异步协程已经执行得相当好了。

对于服务端编程,异步性似乎是Node.js流行的一大原因。我们写的很多代码,特别是那些诸如网站之类的高I/O应用,都依赖于外部资源。这可以是任何资源,包括从远程数据库调用到POST一个REST请求。一旦你请求这些资源的任一一个,你的代码在等待资源响应时便无事可做(译者注:如果没有异步编程的话)。

有了异步编程,在等待这些资源响应的过程中,你的代码便可以去处理其他的任务。

协程(Coroutines)

在Python中,异步函数通常被称作协程,创建一个协程仅仅只需使用async关键字,或者使用@asyncio.coroutine装饰器。下面的任一代码,都可以作为协程工作,形式上也是等同的:

importasyncio

asyncdefping_server(ip):

pass

@asyncio.coroutine

defload_file(path):

pass

上面这俩特殊的函数,在调用时会返回协程对象。熟悉JavaScript中Promise的同学,可以把这个返回对象当作跟Promise差不多。调用他们中的任意一个,实际上并未立即运行,而是返回一个协程对象,然后将其传递到Eventloop中,之后再执行。

如果要判断一个函数是不是协程,asyncio提供了asyncio.iscoroutinefunction(func)方法,如果要判断一个函数返回的是不是协程对象,则可以使用asyncio.iscoroutine(obj)。

Yieldfrom

调用协程的方式有有很多,yieldfrom就是其中的一种。这种方式在Python3.3中被引入,在Python3.5中以async/await的形式进行了优化。yieldfrom表达式的使用方式如下:

importasyncio

@asyncio.coroutine

defget_jason(client,url):

file_content=yieldfromload_file('/Usrs/scott/data.txt')

正如所看到的,yieldfrom被使用在用@asyncio.coroutine装饰的函数内,如果想把yieldfrom在这个函数外使用,将会抛出如下语法错误:

File"main.py",line1

file_content=yieldfromload_file('/Users/scott/data.txt')

^

SyntaxError:'yield'outsidefunction

为了避免语法错误,yieldfrom必须在调用函数的内部使用(这个调用函数通常被装饰为协程)。

Async/await

较新的语法是使用async/await关键字。async从Python3.5开始被引进,跟@asyncio.coroutine装饰器一样,用来声明一个函数是一个协程。只要把它放在函数定义之前,就可以应用到函数上,使用方式如下:

asyncdefping_server(ip):

#pingcodehere...

实际调用这个函数时,使用await而不用yieldfrom,当然,使用方式依然差不多:

asyncdefping_local(ip):

returnawaitping_server('192.168.1.1')

再强调一遍,跟yieldfrom一样,不能在函数外部使用await,否则会抛出语法错误。(译者注:async用来声明一个函数是协程,然后使用await调用这个协程,await必须在函数内部,这个函数通常也被声明为另一个协程)

Python3.5对这两种调用协程的方法都提供了支持,但是推荐async/await作为首选。

EventLoop

如果你还不知道如何开始和操作一个Eventloop,那么上诉有关协程所说的都起不了多大作用。Eventloop在执行异步函数时非常重要,重要到只要执行协程,基本上就得利用Eventloop。

Eventloop提供了相当多的功能:

注册,执行和取消延迟调用(异步函数)

创建客户端与服务端传输用于通信

创建子程序和通道跟其他的程序进行通信

指定函数的调用到线程池

Eventloop有相当多的配置和类型可供使用,但大部分程序只需要如下方式预定函数即可:

importasyncio

asyncdefspeak_async():

print('OMGasynchronicity!')

loop=asyncio.get_event_loop()

loop.run_until_complete(speak_async())

loop.close()

有意思的是代码中的最后三行,首先获取默认的Eventloop(asyncio.get_event_loop()),然后预定和运行异步任务,并在完成后结束循环。

loop.run_until_complete()函数实际上是阻塞性的,也就是在所有异步方法完成之前,它是不会返回的。但因为我们只在一个线程中运行这段代码,它没法再进一步扩展,即使循环仍在运行。

可能你现在还没觉得这有多大的用处,因为我们通过调用其他IO来结束Eventloop中的阻塞(译者注:也就是在阻塞时进行其他IO),但是想象一下,如果在网页服务器上,把整个程序都封装在异步函数内,到时就可以同时运行多个异步请求了。

也可以将Eventloop的线程中断,利用它去处理所有耗时较长的IO请求,而主线程处理程序逻辑或者用户界面。

一个案例

让我们实际操作一个稍大的案例。下面这段代码就是一个非常漂亮的异步程序,它先从Reddit抓取JSON数据,解析它,然后打印出当天来自/r/python,/r/programming和/r/compsci的置顶帖。

所示的第一个方法get_json(),由get_reddit_top()调用,然后只创建一个GET请求到适当的网址。当这个方法和await一起调用后,Eventloop便能够继续为其他的协程服务,同时等待HTTP响应达到。一旦响应完成,JSON数据就返回到get_reddit_top(),得到解析并打印出来。

asyncdefget_reddit_top(subreddit,client):

data1=awaitget_json(client,'https://www.reddit.com/r/'+subreddit+'/top.json?sort=top&t=day&limit=5')

j=json.loads(data1.decode('utf-8'))

foriinj['data']['children']:

score=i['data']['score']

title=i['data']['title']

link=i['data']['url']

print(str(score)+':'+title+'('+link+')')

print('DONE:',subreddit+'\n')

defsignal_handler(signal,frame):

loop.stop()

client.close()

sys.exit(0)

signal.signal(signal.SIGINT,signal_handler)

asyncio.ensure_future(get_reddit_top('python',client))

asyncio.ensure_future(get_reddit_top('programming',client))

asyncio.ensure_future(get_reddit_top('compsci',client))

loop.run_forever()

这跟我们之前展示出来的代码略有不同。为了达到在Eventloop中运行多重协程的目的,我们使用asyncio.ensure_future(),然后运行无限循环以处理一切。

为了保证运行成功,你必须先安装aiohttp,可以使用PIP安装:

pipinstallaiohttp

现在,只要保证你运行的Python3.5或者更高版本,你就可以获得如下输出:

$pythonmain.py

46:Pythonasync/awaitTutorial(http://stackabuse.com/python-async-await-tutorial/)

16:Usinggametheory(andPython)toexplainthedilemmaofexchanginggifts.Turnsout:givingagiftprobablyfeelsbetterthanreceiving

56:WhichversionofPythondoyouuse?(ThisisapolltocomparethepopularityofPython2vs.Python3)(http://strawpoll.me/6299023

DONE:python

71:TheSemanticsofVersionControl-WouterSwierstra(http://www.staff.science.uu.nl/~swier004/Talks/vc-semantics-15.pdf)

25:Favoritenon-textbookCSbooks(https://www.reddit.com/r/compsci/comments/3xag9e/favorite_nontextbook_cs_books/)

13:CompSciWeekendSuperThread(December18,2015)(https://www.reddit.com/r/compsci/comments/3xacch/compsci_weekend_superthread_december_18

DONE:compsci

1752:684.8TBofdataisupforgrabsduetopubliclyexposedMongoDBdatabases(https://blog.shodan.io/its-still-the-data-stupid/)

773:Instagram'sMillionDollarBug?(http://exfiltrated.com/research-Instagram-RCE.php)

387:AmazinglysimpleexplanationofDiffie-Hellman.Hischannelhastonsofamazingvideosandonlyafewviews:(thoughtIwouldshare!(h

DONE:programming

注意,如果多次运行这段代码,打印出来的subreddit数据在顺序上会有些许变化。这是因为每当我们调用一次代码都会释放对线程的控制,容许线程去处理另一个HTTP调用。这将导致谁先获得响应,谁就先打印出来。

结论

即使Python内置的异步操作没有Javascript那么顺畅,但这并不意味着就不能用它来把应用变得更有趣、更有效率。只要花半个小时的时间去了解它的来龙去脉,你就会感觉把异步操作应用到你的程序中将会是多美好的一件事。

 

  Python培训Python培训班Python培训机构,就选光环大数据!

  还不够过瘾?想学习更多?点击 http://hadoop.aura.cn/python/ 进行Python学习!


大数据培训、人工智能培训、Python培训、大数据培训机构、大数据培训班、数据分析培训、大数据可视化培训,就选光环大数据!光环大数据,聘请专业的大数据领域知名讲师,确保教学的整体质量与教学水准。讲师团及时掌握时代潮流技术,将前沿技能融入教学中,确保学生所学知识顺应时代所需。通过深入浅出、通俗易懂的教学方式,指导学生更快的掌握技能知识,成就上万个高薪就业学子。 更多问题咨询,欢迎点击------>>>>在线客服

你可能也喜欢这些

在线客服咨询

领取资料

X
立即免费领取

请准确填写您的信息

点击领取
#第三方统计代码(模版变量) '); })();
'); })();