我的以下功能正常运行,但由于某种原因,请求似乎是同步执行的,而不是异步执行的。
我现在的假设是,这是因为 main 函数中的 for record in records
for 循环而发生的,但我不确定如何更改它以便请求可以异步执行。如果不是这种情况,我还需要更改什么?
async def do_request(query_string):
base_url = 'https://maps.googleapis.com/maps/api/place/textsearch/json?'
params = {'key': google_api_key,
'query': query_string}
async with aiohttp.ClientSession() as session:
async with session.request('GET', base_url, params=params) as resp:
return resp
async def main():
create_database_and_tables()
records = prep_sample_data()[:100]
for record in records:
r = Record(record)
if not r.is_valid:
continue
query_string = r.generate_query_string()
resp = await do_request(query_string)
print("NOW WRITE TO DATABASE")
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
最佳答案
您正在依次等待单独的 do_request()
调用。不要直接等待它们(在协程完成之前阻塞),而是使用 asyncio.gather()
function让事件循环同时运行它们:
async def main():
create_database_and_tables()
records = prep_sample_data()[:100]
requests = []
for record in records:
r = Record(record)
if not r.is_valid:
continue
query_string = r.generate_query_string()
requests.append(do_request(query_string))
for resp in asyncio.gather(*requests):
print("NOW WRITE TO DATABASE")
asyncio.gather()
返回值是协程返回的所有结果的列表,其顺序与您将它们传递给 gather()
函数的顺序相同。
如果您需要原始记录来处理响应,您可以通过几种不同的方式将记录和查询字符串配对:
- 将有效记录存储在单独的列表中,并在处理响应时使用
zip()
将它们再次配对 - 使用辅助协程获取有效记录、生成查询字符串、调用请求并将记录和响应作为元组一起返回。
您还可以将响应处理混合到一个聚集的协程中;一个获取记录,生成查询字符串,等待 do_request
,然后在响应准备好时将结果存储在数据库中。
换句话说,将需要连续发生的工作分配到协程中,然后将它们收集起来。
关于使用 aiohttp 的 Python 3.6 异步 GET 请求同步运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49118449/