#python-3.x #multithreading #python-asyncio
#python-3.x #многопоточность #python-asyncio
Вопрос:
Мне нужно получить некоторые цены для внешнего API, одну за другой для дюжины объектов, и это займет 2-3 секунды для каждого запроса, так что это может стать довольно долгим.
Я (вроде) знал, как сделать многопоточность на python, я реализовал это, и это работает нормально, и это довольно быстро.
Затем я недавно обнаружил asyncio, и, похоже, это может быть полезно в моей ситуации вместо открытия нескольких потоков. Итак, я попытался «преобразовать» свой многопоточный код в код, использующий asyncio, как вы можете видеть ниже, прочитав несколько примеров. Но когда testOne
не работает и ошибка Task exception was never retrieved
. Я почистил код для лучшего понимания (дайте мне знать, если вам понадобится дополнительная информация).
from threading import Thread
import asyncio
### ASYNC MULTI THREAD ####
def prixMulti(client, symbol, prix):
prix[symbol] = # API price request using client
def testMulti(client, sql):
prix = {}
objects = # Database request using sql
listeThread = []
for object in objects:
listeThread.append(Thread(target=prixMulti, args=(client, object['name'], prix)))
for t in listeThread:
t.start()
for t in listeThread:
t.join()
print(prix)
#### ASYNC ONE THREAD ####
async def prixOne(client, symbol):
return #same API price request using client
async def prixOneWait(client, symbol, prix):
prix[symbol] = await prixOne(client, symbol)
def testOne(client, sql):
prix = {}
objects = # Database request using sql
tasks = []
loop = asyncio.get_event_loop()
for object in objects:
tasks.append(loop.create_task(prixOneWait(client, prix, object['nom'] )))
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
print(prix)
# Some code to initialise client and sql
testMulti(client, sql)
testOne(client, sql)
Комментарии:
1. «тот же запрос цены API» в
prixOne
звучит не совсем правильно. Вы должны использовать асинхронный API иawait
его результат. В частности, вы не должны вызывать блокирующие функции изasync def
, и вы почти наверняка захотите чего-то ожидать (или функцией с таким же успехом может быть sync).2. Я не могу изменить API, поскольку он внешний, возможно ли сделать его асинхронным ?!
3. Вы не можете сделать API асинхронным как пользователь API; он должен быть разработан и реализован как асинхронный с нуля. Самое близкое, что вы можете сделать, это использовать
loop.run_in_executor
для передачи функции пулу потоков, но тогда вы снова используете потоки под капотом и не получаете преимуществ asyncio. Если у вас есть только API синхронизации, я бы порекомендовалconcurrent.futures
модуль, в котором есть пул потоков и приятные примитивы для работы с ним.