为了账号安全,请及时绑定邮箱和手机立即绑定

api请求的初学者异步/等待问题

api请求的初学者异步/等待问题

慕侠2389804 2023-05-23 10:48:13
我想加快一些 API 请求...为此,我试图弄清楚如何做并复制一些运行的代码,但是当我尝试自己的代码时,它不再是异步的。也许有人发现失败?复制代码(从计算器中猜测):#!/usr/bin/env python3import asyncio@asyncio.coroutinedef func_normal():    print('A')    yield from asyncio.sleep(5)    print('B')    return 'saad'@asyncio.coroutinedef func_infinite():    for i in range(10):        print("--%d" % i)    return 'saad2'loop = asyncio.get_event_loop()tasks = func_normal(), func_infinite()a, b = loop.run_until_complete(asyncio.gather(*tasks))print("func_normal()={a}, func_infinite()={b}".format(**vars()))loop.close()我的“自己的”代码(最后我需要返回一个列表并合并所有函数的结果):import asyncioimport time@asyncio.coroutinedef say_after(start,count,say,yep=True):    retl = []    if yep:        time.sleep(5)    for x in range(start,count):        retl.append(x)        print(say)    return retldef main():    print(f"started at {time.strftime('%X')}")            loop = asyncio.get_event_loop()    tasks = say_after(10,20,"a"), say_after(20,30,"b",False)    a, b = loop.run_until_complete(asyncio.gather(*tasks))    print("func_normal()={a}, func_infinite()={b}".format(**vars()))    loop.close()    c =  a + b    #print(c)    print(f"finished at {time.strftime('%X')}")main()或者我完全错了,应该用多线程解决这个问题?对于返回我需要合并的列表的 API 请求,最好的方法是什么?
查看完整描述

1 回答

?
慕虎7371278

TA贡献1802条经验 获得超4个赞

为每个需要改进的部分添加了评论。删除了一些简单的代码。


事实上,我没有发现 using range()wrapped in coroutine 和使用async def, 可能值得更重的操作有任何性能提升。


import asyncio

import time


# @asyncio.coroutine IS DEPRECATED since python 3.8

@asyncio.coroutine

def say_after(wait=True):

    result = []


    if wait:

        print("I'm sleeping!")

        time.sleep(5)

        print("'morning!")

        # This BLOCKs thread, but release GIL so other thread can run.

        # But asyncio runs in ONE thread, so this still harms simultaneity.


    # normal for is BLOCKING operation.

    for i in range(5):

        result.append(i)

        print(i, end='')

    print()


    return result



def main():

    start = time.time()


    # Loop argument will be DEPRECATED from python 3.10

    # Make main() as coroutine, then use asyncio.run(main()).

    # It will be in asyncio Event loop, without explicitly passing Loop.

    loop = asyncio.get_event_loop()

    tasks = say_after(), say_after(False)


    # As we will use asyncio.run(main()) from now on, this should be await-ed.

    a, b = loop.run_until_complete(asyncio.gather(*tasks))


    print(f"Took {time.time() - start:5f}")


    loop.close()



main()

更好的方法:


import asyncio

import time



async def say_after(wait=True):

    result = []


    if wait:

        print("I'm sleeping!")

        await asyncio.sleep(2)  # 'await' a coroutine version of it instead.

        print("'morning!")


    # wrap iterator in generator - or coroutine

    async def asynchronous_range(end):

        for _i in range(end):

            yield _i


    # use it with async for

    async for i in asynchronous_range(5):

        result.append(i)

        print(i, end='')

    print()


    return result



async def main():

    start = time.time()


    tasks = say_after(), say_after(False)

    a, b = await asyncio.gather(*tasks)


    print(f"Took {time.time() - start:5f}")



asyncio.run(main())


结果

你的代码:


DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead

  def say_after(wait=True):

I'm sleeping!

'morning!

01234

01234

Took 5.003802

更好的异步代码:


I'm sleeping!

01234

'morning!

01234

Took 2.013863

请注意,固定代码现在在其他任务休眠时完成其工作。


查看完整回答
反对 回复 2023-05-23
  • 1 回答
  • 0 关注
  • 104 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信