何时使用以及何时不使用 Python 3.5 `await`?

2024-12-24 08:56:00
admin
原创
73
摘要:问题描述:我了解 Python 3.5 中的使用流程asyncio,但我没有看到关于我应该执行什么操作、不应该执行什么操作或哪些操作可以忽略不计的描述。我是否只需要根据“这是一个 IO 操作,因此应该执行”await做出最佳判断?await解决方案 1:默认情况下,所有代码都是同步的。您可以使用 定义函数并将...

问题描述:

我了解 Python 3.5 中的使用流程asyncio,但我没有看到关于我应该执行什么操作、不应该执行什么操作或哪些操作可以忽略不计的描述。我是否只需要根据“这是一个 IO 操作,因此应该执行”await做出最佳判断?await


解决方案 1:

默认情况下,所有代码都是同步的。您可以使用 定义函数并将其async def“调用”这些函数,从而使其异步await。更正确的问题是“我什么时候应该编写异步代码而不是同步代码?”。答案是“当你能从中受益时”。正如您所指出的那样,在您使用 I/O 操作的情况下,您通常会受益:

# Synchronous way:
download(url1)  # takes 5 sec.
download(url2)  # takes 5 sec.
# Total time: 10 sec.

# Asynchronous way:
await asyncio.gather(
    async_download(url1),  # takes 5 sec. 
    async_download(url2)   # takes 5 sec.
)
# Total time: only 5 sec. (+ little overhead for using asyncio)

当然,如果你创建了一个使用异步代码的函数,那么这个函数也应该是异步的(应该定义为async def)。但是任何异步函数都可以自由使用同步代码。如果没有理由,将同步代码强制转换为异步是没有意义的:

# extract_links(url) should be async because it uses async func async_download() inside
async def extract_links(url):  

    # async_download() was created async to get benefit of I/O
    html = await async_download(url)  

    # parse() doesn't work with I/O, there's no sense to make it async
    links = parse(html)  

    return links

一个非常重要的事情是,任何长时间的同步操作(例如,> 50 毫秒,很难确切地说)都会冻结该时间内的所有异步操作:

async def extract_links(url):
    data = await download(url)
    links = parse(data)
    # if search_in_very_big_file() takes much time to process,
    # all your running async funcs (somewhere else in code) will be frozen
    # you need to avoid this situation
    links_found = search_in_very_big_file(links)

您可以避免在单独的进程中调用长时间运行的同步函数(并等待结果):

executor = ProcessPoolExecutor(2)

async def extract_links(url):
    data = await download(url)
    links = parse(data)
    # Now your main process can handle another async functions while separate process running    
    links_found = await loop.run_in_executor(executor, search_in_very_big_file, links)

再举一个例子:当你需要requests在 asyncio 中使用时。requests.get只是同步长时间运行的函数,你不应该在异步代码中调用它(再次强调,为了避免冻结)。但它运行时间长是因为 I/O,而不是因为长时间计算。在这种情况下,你可以使用ThreadPoolExecutor而不是ProcessPoolExecutor来避免一些多处理开销:

executor = ThreadPoolExecutor(2)

async def download(url):
    response = await loop.run_in_executor(executor, requests.get, url)
    return response.text

解决方案 2:

你没有太多自由。如果你需要调用一个函数,你需要找出这是一个普通函数还是一个协程。await当且仅当你调用的函数是协程时,你才必须使用关键字。

如果async涉及函数,则应该有一个“事件循环”来协调这些async函数。严格来说,这不是必需的,您可以“手动”运行async向其发送值的方法,但您可能不想这样做。事件循环会跟踪尚未完成的协程并选择下一个继续运行的协程。asyncio模块提供了事件循环的实现,但这不是唯一可能的实现。

考虑以下两行代码:

x = get_x()
do_something_else()

x = await aget_x()
do_something_else()

语义完全相同:调用一个产生某个值的方法,当值准备好时将其分配给变量x并执行其他操作。在这两种情况下,do_something_else只有在前一行代码完成后才会调用该函数。这甚至不意味着在异步方法执行之前、之后或期间,aget_x控制权将被移交给事件循环。

但仍存在一些差异:

  • 第二个代码片段只能出现在另一个async函数内

  • aget_x函数不是通常的,而是协程(即用async关键字声明或装饰为协程)

  • aget_x能够与事件循环“通信”:即向其产生一些对象。事件循环应该能够将这些对象解释为执行某些操作的请求(例如发送网络请求并等待响应,或者只是暂停此协程几n秒钟)。通常的get_x函数无法与事件循环通信。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1124  
  IPD(Integrated Product Development,集成产品开发)流程是一种广泛应用于高科技和制造业的产品开发方法论。它通过跨职能团队的紧密协作,将产品开发周期缩短,同时提高产品质量和市场成功率。在IPD流程中,CDCP(Concept Decision Checkpoint,概念决策检查点)是一个关...
IPD培训课程   79  
  研发IPD(集成产品开发)流程作为一种系统化的产品开发方法,已经在许多行业中得到广泛应用。它不仅能够提升产品开发的效率和质量,还能够通过优化流程和资源分配,显著提高客户满意度。客户满意度是企业长期成功的关键因素之一,而IPD流程通过其独特的结构和机制,能够确保产品从概念到市场交付的每个环节都围绕客户需求展开。本文将深入...
IPD流程   70  
  IPD(Integrated Product Development,集成产品开发)流程是一种以跨职能团队协作为核心的产品开发方法,旨在通过优化资源分配、提高沟通效率以及减少返工,从而缩短项目周期并提升产品质量。随着企业对产品上市速度的要求越来越高,IPD流程的应用价值愈发凸显。通过整合产品开发过程中的各个环节,IPD...
IPD项目管理咨询   82  
  跨部门沟通是企业运营中不可或缺的一环,尤其在复杂的产品开发过程中,不同部门之间的协作效率直接影响项目的成败。集成产品开发(IPD)作为一种系统化的项目管理方法,旨在通过优化流程和增强团队协作来提升产品开发的效率和质量。然而,跨部门沟通的复杂性往往成为IPD实施中的一大挑战。部门之间的目标差异、信息不对称以及沟通渠道不畅...
IPD是什么意思   74  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用