草庐IT

python - Python 3.5 中协程和 future /任务之间的区别?

coder 2023-05-20 原文

假设我们有一个虚拟函数:

async def foo(arg):
    result = await some_remote_call(arg)
    return result.upper()

两者有什么区别:

import asyncio    

coros = []
for i in range(5):
    coros.append(foo(i))

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(coros))

还有:

import asyncio

futures = []
for i in range(5):
    futures.append(asyncio.ensure_future(foo(i)))

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(futures))

注意:示例返回结果,但这不是问题的重点。当返回值很重要时,使用 gather() 而不是 wait()

无论返回值如何,我都在寻找关于 ensure_future() 的清晰度。 wait(coros)wait(futures) 都运行协程,那么协程何时以及为什么应该包含在 ensure_future 中?

基本上,使用 Python 3.5 的 async 运行一堆非阻塞操作的正确方法 (tm) 是什么?

为了获得额外的信用,如果我想批量调用怎么办?例如,我需要调用 some_remote_call(...) 1000 次,但我不想用 1000 个同时连接来破坏 Web 服务器/数据库/等。这对于线程或进程池是可行的,但是有没有办法使用 asyncio 来做到这一点?

2020 年更新(Python 3.7+):不要使用这些代码段。而是使用:

import asyncio

async def do_something_async():
    tasks = []
    for i in range(5):
        tasks.append(asyncio.create_task(foo(i)))
    await asyncio.gather(*tasks)

def do_something():
    asyncio.run(do_something_async)

还可以考虑使用 Trio ,asyncio 的强大的第 3 方替代方案。

最佳答案

协程是一个生成器函数,它既可以产生值,也可以接受来自外部的值。使用协程的好处是我们可以暂停函数的执行并在以后恢复它。在网络操作的情况下,在我们等待响应时暂停函数的执行是有意义的。我们可以利用这段时间来运行一些其他的功能。

future 就像 Javascript 中的 Promise 对象。它就像一个占位符,用于表示将来会实现的值。在上面提到的情况下,在等待网络 I/O 时,一个函数可以给我们一个容器,这是一个 promise ,当操作完成时它将用该值填充容器。我们保留 future 对象,当它完成时,我们可以调用它的方法来检索实际结果。

直接回答:如果您不需要结果,则不需要 ensure_future。如果您需要结果或检索发生的异常,它们很好。

额外积分:我会选择 run_in_executor并传递一个 Executor 实例来控制最大工作人员的数量。

说明和示例代码

在第一个示例中,您使用的是协程。 wait 函数需要一堆协程并将它们组合在一起。所以 wait() 在所有协程都用尽时完成(完成/完成返回所有值)。

loop = get_event_loop() # 
loop.run_until_complete(wait(coros))

run_until_complete 方法将确保循环在执行完成之前一直处于事件状态。请注意在这种情况下您如何没有获得异步执行的结果。

在第二个例子中,你使用 ensure_future 函数来包装一个协程并返回一个 Task 对象,它是一种 Future .当您调用 ensure_future 时,协程计划在主事件循环中执行。返回的 future/task 对象还没有值,但随着时间的推移,当网络操作完成时,future 对象将保存操作的结果。

from asyncio import ensure_future

futures = []
for i in range(5):
    futures.append(ensure_future(foo(i)))

loop = get_event_loop()
loop.run_until_complete(wait(futures))

所以在这个例子中,我们在做同样的事情,除了我们使用 future 而不是仅仅使用协程。

我们来看一个如何使用 asyncio/coroutines/futures 的例子:

import asyncio


async def slow_operation():
    await asyncio.sleep(1)
    return 'Future is done!'


def got_result(future):
    print(future.result())

    # We have result, so let's stop
    loop.stop()


loop = asyncio.get_event_loop()
task = loop.create_task(slow_operation())
task.add_done_callback(got_result)

# We run forever
loop.run_forever()

在这里,我们在 loop 对象上使用了 create_task 方法。 ensure_future 将在主事件循环中安排任务。这种方法使我们能够在我们选择的循环上调度协程。

我们还看到了在任务对象上使用 add_done_callback 方法添加回调的概念。

当协程返回值、引发异常或被取消时,Taskdone。有一些方法可以检查这些事件。

我写了一些关于这些主题的博客文章,可能会有所帮助:

当然,您可以在官方手册中找到更多详细信息:https://docs.python.org/3/library/asyncio.html

关于python - Python 3.5 中协程和 future /任务之间的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34753401/

有关python - Python 3.5 中协程和 future /任务之间的区别?的更多相关文章

  1. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  4. ruby - 如何使用 RSpec::Core::RakeTask 创建 RSpec Rake 任务? - 2

    如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake

  5. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  6. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

    我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

  7. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  8. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  9. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  10. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

随机推荐