На данный момент у меня есть скрипт python, который делает http-запрос к микросервису. Запрос занимает в среднем 3 секунды.
Это мой скрипт Python в обобщенном виде.
def main():
response = request_to_MS(url)
# This process does not need the response of the microservice.
some_process()
# This is where i actually need a response from the microservice
do_something_with_response(response)
main()
Я хотел бы, чтобы мой скрипт мог продолжить работу с кодом и дождаться ответа на запрос позже, аналогично машинописному тексту.
/**
* I'd like to write this kind of code in python.
*/
function get_data(): Promise<string>{
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('This is resolved');
})
})
}
async function main(){
const data = get_data();
console.info('Data variable stores my promise ', data);
// Some process
[1, 2, 3, 4, 5, 6 ,7 ,8].forEach((x: number) => console.info(x));
// I need the promise value here
console.info('En el await', (await data).length)
}
void main();
В основном то, что я ищу, это то, что время, необходимое для завершения выполнения процесса, и время отклика микросервиса перекрываются, что позволяет в целом улучшить время отклика.
Сделайте request_to_MS(url)
сопрограммой async def
, запланируйте ее как задачу с response = asyncio.create_task(request_to_MS(url))
.
Он начнет выполняться. Теперь можно продолжать бегать some_process()
. Когда вам нужно response
, просто сделайте
do_something_with_response(await response)
редактировать: вышеизложенное будет работать только в том случае, если main также является async def
, так как вы можете использовать await
только в асинхронной функции. Вместо того, чтобы звонить main()
, звоните asyncio.run(main())
.
Всего:
async def request_to_MS(url):
await asyncio.sleep(3)
return 'some internet data'
async def main():
response = asyncio.create_task(request_to_MS(url))
# response is now a Task
some_process()
# if response isn't done running yet, this line will block until it is
do_something_with_response(await response)
asyncio.run(main())
Важное предостережение: some_process
не обязательно должна быть сопрограммой, но если это блокирующая функция (либо процессором, либо вводом-выводом), она никогда не даст никаких циклов для запуска response
. Если он блокируется через ввод-вывод, подумайте о том, чтобы сделать его также сопрограммой. Если нет асинхронной поддержки для любых низкоуровневых операций ввода-вывода, которые он выполняет, или если он привязан к ЦП, рассмотрите возможность использования run_in_executor asyncio.
Знаете ли вы, как поделиться моим примером кода в этом посте? Это сделано для того, чтобы любой, кто зайдет на этот пост, мог увидеть окончательный результат.
Этот скрипт работает на ограниченной машине с 1 процессором, будет ли он работать так же, когда я загружу его в рабочую среду?
run_in_executor
использует пул потоков, поэтому вы можете запускать все, что угодно, но ваша производительность будет не лучше, чем при использовании потоков. Если это нацелено на машину с одним процессором, использование нескольких потоков вообще не улучшит вашу производительность. Вместо этого asyncio — это парадигма «совместной многозадачности». Все сопрограммы выполняются в асинхронном цикле, который выполняется в одном потоке, избегая накладных расходов на потоки, но при этом выполняя многозадачность. Подвох: тот, кто создал используемую вами библиотеку ввода-вывода, должен явно поддерживать asyncio.
Итак, общее эмпирическое правило: если вы можете запустить его как задачу, вы должны это сделать, так как это будет иметь минимальные накладные расходы. Если операция ввода-вывода не поддерживает низкоуровневую асинхронную поддержку, вам придется run_in_executor
что приведет к немного большим накладным расходам. Я бы почитал об асинхронности Python, потому что его поведение может иногда немного сбивать с толку, но как только вы «поймете его», я думаю, что это имеет большой смысл. Что касается вашего кода, я бы просто отредактировал его в исходном вопросе в конце, и я был бы признателен, если бы вы приняли мой ответ.
В моем случае у меня есть функция блокировки ввода-вывода
request_to_MS
и функция блокировки процессораsome_process
. Как было предложено, я использовалrun_in_executor
для запускаsome_process
и, похоже, получил ожидаемые результаты. Теперь возникает вопрос, почему бы не использоватьrun_in_executor
илиcreate_task
в обоих случаях?