[英]Python 3.6 async GET requests in with aiohttp are running synchronously
我有以下功能正常,但由於某種原因,請求似乎是同步執行,而不是異步。
我現在的假設是,這是因為main函數中的for循環for record in records
的for record in records
,但我不知道如何更改它以便請求可以執行異步。 如果不是這樣,我還需要改變什么呢?
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()
函數讓事件循環同時運行它們:
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()
返回值是coroutines返回的所有結果的列表,其順序與您將它們傳遞給gather()
函數的順序相同。
如果您需要原始記錄來處理響應,您可以通過幾種不同的方式配對記錄和查詢字符串:
zip()
將它們再次配對 您還可以將響應處理混合到聚集的協程中; 一個記錄,生成查詢字符串,等待do_request
,然后在響應准備好時將結果存儲在數據庫中。
換句話說,將你需要連續發生的工作分成協同程序並收集它們。
建立Martijn的答案
如果請求的順序對您來說無關緊要(當它寫入數據庫時),您可以在獲取命令時將響應寫入數據庫。
編輯(解釋更多):我在這里使用2個信號量。 1是通過aiohttp限制連接數。 這取決於您的系統。 大多數Linux系統默認為1024.根據我自己的個人經驗,將其設置為低於OS max是更可取的。
max_coroutines
是解決一次運行太多協程的問題。
我使用asyncio.ensure_future()
以便在構建列表時運行協同程序。 這樣,在執行任何協同程序之前,您不會創建完整的協程列表。
# Limit the total number of requests you make by 512 open connections.
max_request_semaphore = asyncio.BoundedSemaphore(512)
max_coroutines = asyncio.BoundedSemaphore(10000)
async def process_response(response):
print('Process your response to your database')
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 max_request_semaphore:
async with aiohttp.ClientSession() as session:
async with session.request('GET', base_url, params=params) as resp:
return resp
# Excuse me for the bad function naming
async do_full_request(query_string):
resp = await do_request(query_string)
await process_response(resp)
max_coroutines.release()
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()
# Will prevent more than 10k coroutines created.
await max_coroutines.acquire()
requests.append(
asyncio.ensure_future(
do_full_request(query_string)))
# Now gather all the coroutines
await asyncio.gather(*requests)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.