0

我正在尝试加速一些调用 an 的代码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 分钟才能执行。我在这里做错了什么,还是三重奏/异步之类的东西不适合我的问题设置?

4

1 回答 1

0

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

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

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

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

于 2020-06-27T16:14:03.543 回答