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



我想加速一些API请求。。。为此,我试图找出如何做和复制一些运行的代码,但当我尝试自己的代码时,它不再是异步的。也许有人发现了失败?

复制代码(从stackoverflow猜测(:

#!/usr/bin/env python3
import asyncio
@asyncio.coroutine
def func_normal():
print('A')
yield from asyncio.sleep(5)
print('B')
return 'saad'
@asyncio.coroutine
def 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 asyncio
import time

@asyncio.coroutine
def 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 retl

def 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请求,最好的方法是什么?

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

事实上,我没有发现使用封装在协程中的range()和使用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

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

最新更新