前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python3.7的进化-异步编程

Python3.7的进化-异步编程

作者头像
哒呵呵
发布2019-01-23 16:47:19
2.7K0
发布2019-01-23 16:47:19
举报
文章被收录于专栏:鸿的学习笔记

编译自 https://tryexceptpass.org/article/asyncio-in-37/

导论

asyncio相关模块已经成为Python很核心的一部分,aio-libs一直在持续的发展中,例如aiohttp、aiopg等库已经可以初步的在生产环境使用了。在Python3.7中,引入了一系列的与asyncio相关变化,这些变化聚焦在代码质量,让开发者尽量地减少工作量和获得更好的性能体验,主要内容包括了<新的保留字>、<环境变量>、<新的asyncio.run()函数>、<更简单的任务管理、时间循环管理>、<回调更新>、<异步的上下文管理器>等。

新的保留字

Python3.7中 async和await 成为了关键字,这也意味着async和await不能成为变量名字了。如果在之前的代码里包含了async和await的变量命令,那么迁移到3.7就需要改变命名了。

代码语言:javascript
复制
# This is a syntax error
def do_some_long_op(async=True):
    ...

# This is not
def do_some_long_op(async_=True):
    ...

do_something()

# This is also a syntax error
async = 'this work could be asynchronous'

# This is not
async_ = 'this work could be asynchronous'

do some_other_thing()

上下文变量(Context Variables)

上下文变量是在3.7新引入的特性,类似于全局变量,只不过这个全局变量针对于所有任务。下面代码的含义是一个异步服务在新的客户端发起连接时执行handle_request()函数,此时会设置client_addr_var变量,这样的话就不需要传递变量给render_goodbye()函数,而可以直接访问ContextVar类,获得变量。这个包存在的意义在于保存异步环境下的各种状态,简化参数传递等操作。

代码语言:javascript
复制
import asyncio
import contextvars

client_addr_var = contextvars.ContextVar('client_addr')

def render_goodbye():
    # The address of the currently handled client can be accessed
    # without passing it explicitly to this function.

    client_addr = client_addr_var.get()
    return f'Good bye, client @ {client_addr}\n'.encode()

async def handle_request(reader, writer):
    addr = writer.transport.get_extra_info('socket').getpeername()
    client_addr_var.set(addr)

    # In any code that we call is now possible to get
    # client's address by calling 'client_addr_var.get()'.

    while True:
        line = await reader.readline()
        ...

    writer.write(render_goodbye())
    writer.close()

async def main():
    srv = await asyncio.start_server(handle_request, '127.0.0.1', 8081)

    async with srv:
        await srv.serve_forever()

asyncio.run(main())

代码质量提升

新的asyncio.run()函数

这个函数旨在简化get_event_loop、run_until_complete、close的模板代码。

代码语言:javascript
复制
async def some_async_task():
    ...

# Before Python 3.7
loop = asyncio.get_event_loop()
loop.run_until_complete(some_async_task())
loop.close()

# After Python 3.7
asyncio.run(some_async_task())
更简单的任务管理、时间循环管理

任务管理牵扯到任务创建、维护和关闭,最常调用的current_task()和all_tasks()两个函数从asyncio.Task移出(相关接口被设置废弃状态)。

代码语言:javascript
复制
try:
    loop.run_forever()

except KeyboardInterrupt:
    # Canceling pending tasks and stopping the loop

    # Previous to Python 3.7
    asyncio.gather(*asyncio.Task.all_tasks()).cancel()

    # After the changes in 3.7
    asyncio.gather(*asyncio.all_tasks()).cancel()

之前的事件循环只有asyncio.get_event_loop()一个函数,但是3.7新加的asyncio.get_running_loop()会获得一个正在运行的事件循环(如果不存在就会抛出RuntimeError错误),这个主要是为了方便解耦各个模块之间的事件循环。

回调更新(callback update)

当使用call_soon()或者是call_soon_threadsafe()函数时一般而言只是拿到Handle对象,而无法确定此次回调是否被取消,3.7新加入了Handle.cancelled()方法以确定此次回调是否已经取消。

异步上下文管理

这个和Python之前的上下文管理器类似,就是with语法。只不过之前的异步上下文需要实现标准的aenter__() or __aexit()方法,现在可以和非异步环境下的contextmanager()装饰器一样,使用yield语法。

代码语言:javascript
复制
from contextlib import asynccontextmanager

@asynccontextmanager()
async def login(username, password):
    # Wait for the login to complete and return the token
    token = await _login_to_web_api(username, password)
    try:
        # Execute the context block
        yield token
    finally:
        # Logout
        await _logout_from_web_api(token)

async def list_resources():
    async with login(username, password) as token:
        # We are now logged in and have a valid token
        return await list_resources(token)
代码语言:javascript
复制

性能提升

asyncio.get_event_loop()、asyncio.gather()、asyncio.sleep()和Future的回调管理都有不错的性能提升。主要原因还是在于有些函数用C重写了。

后记

其他相关更新省略了,因为如果不是类似于开发库包的作者,应该都不会用到,上面的就是日常可能会用到的更新。由于这些更新异步编程在Python3.7中获得了极好的体验提升,正如Python之禅所述:

Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-01-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 鸿的学习笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导论
  • 新的保留字
  • 上下文变量(Context Variables)
  • 代码质量提升
    • 新的asyncio.run()函数
      • 更简单的任务管理、时间循环管理
      • 回调更新(callback update)
      • 异步上下文管理
      • 性能提升
      • 后记
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档