【问题标题】:How to use Trio for fast web api calls?如何使用 Trio 进行快速 Web api 调用?
【发布时间】:2020-06-27 13:20:49
【问题描述】:

我正在尝试加快一些调用 api_caller() 的代码,这是一个生成器,您可以对其进行迭代以获得结果。

我的同步代码如下所示:

def process_comment_tree(p):
    # time consuming breadth first search that makes another api call...
    return

def process_post(p):
    process_comment_tree(p)

def process_posts(kw):
    for p in api_caller(query=kw): #possibly 1000s of results
        process_post(p)
    
def process_kws(kws):
    for kw in kws:
        process_posts(kw)

process_kws(kws=['python', 'threads', 'music'])

当我在kws 的长列表上运行此代码时,大约需要 18 分钟才能完成。

当我使用线程时:

with concurrent.futures.ThreadPoolExecutor(max_workers=len(KWS)) as pool:
    for result in pool.map(process_posts, ['python', 'threads', 'music']):
        print(f'result: {result}')

代码在大约 3 分钟内完成。

现在,我第一次尝试使用 Trio,但遇到了麻烦。

async def process_comment_tree(p):
    # same as before...
    return

async def process_post(p):
    await process_comment_tree(p)

async def process_posts(kw):
    async with trio.open_nursery() as nursery:
        for p in r.api.search_submissions(query=kw)
            nursery.start_soon(process_post, p)
    
async def process_kws(kws):
    async with trio.open_nursery() as nursery:
        for kw in kws:
            nursery.start_soon(process_posts, kw)
trio.run(process_kws, ['python', 'threads', 'music'])

这仍然需要大约 18 分钟才能执行。我在这里做错了什么,还是三重奏/异步之类的东西不适合我的问题设置?

【问题讨论】:

  • 这个r.api.search_submissions 似乎是一个同步调用,它会阻塞,所以你一次只能运行一个。
  • 是的,似乎是这样。如果不深入研究外部api,就没有办法解决这个问题吗?为什么线程版的速度这么快?

标签: python multithreading asynchronous python-trio


【解决方案1】:

Trio 和一般的异步库通过在等待外部事件(例如 API 调用)时切换到不同的任务来工作。在您的代码示例中,看起来您开始了一堆任务,但等待外部的东西。我建议阅读本教程的这一部分;它给出了这意味着什么的想法:https://trio.readthedocs.io/en/stable/tutorial.html#task-switching-illustrated

基本上,您的代码必须调用一个函数,将控制权传递回run 循环,以便它可以切换到不同的任务。

如果您的 api_caller 生成器调用外部 API,那么您可以将其替换为异步调用。您需要使用异步 http 库,例如 HTTPXhip

另一方面,如果您的代码中没有任何东西需要等待外部的东西,那么异步不会帮助您的代码运行得更快。

【讨论】:

  • api_caller 是第三方库的一部分。您是说我需要编辑该代码才能使其正常工作吗?为什么线程版本这么快?
  • 您可以使用 Trio 的 run_sync 函数使其与 Trio 一起使用:trio.readthedocs.io/en/stable/… Trio 和线程之间的区别在于线程无需您请求即可切换。这会使处理竞争条件变得困难(有关其他要点,请参阅stackoverflow.com/questions/4024056/threads-vs-async)。本质上,在 Trio 中,你必须告诉 Trio“我在等待什么,现在继续运行其他的”,而对于线程,它无论如何都会不断地来回切换,所以你不必告诉它你在等待。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 1970-01-01
  • 2021-07-27
  • 1970-01-01
  • 2018-12-23
  • 2017-12-15
相关资源
最近更新 更多