Я пытаюсь сделать это:
«Цикл событий запускается в потоке (обычно в основном потоке) и выполняет все обратные вызовы и задачи в своем потоке. Пока задача выполняется в цикле событий, никакие другие задачи не могут выполняться в том же потоке. Когда задача выполняет ожидание выражение, работающая задача приостанавливается, и цикл обработки событий выполняет следующую задачу».
https://docs.python.org/3/library/asyncio-dev.html#concurrency-and-multithreading
И я сделал этот уродливый пример:
import asyncio
async def print_message(message):
print(message)
async def int_sum(a, b):
await print_message('start_sum')
result = a + b
await print_message('end_sum')
return result
async def int_mul(a, b):
await print_message('start_mul')
result = a * b
await print_message('end_mul')
return result
async def main():
result = await asyncio.gather(int_sum(4, 3), int_mul(4, 3))
print(result)
asyncio.run(main())
С "последовательными" результатами:
$ python async_test.py
start_sum
end_sum
start_mul
end_mul
[7, 12]
Но мне нужен вывод, похожий на коррутину:
$ python async_test.py
start_sum
start_mul
end_sum
end_mul
[7, 12]
Как я могу это сделать?
Примечание: я не ищу пример asyncio.sleep(n), я ищу
«Когда задача выполняет выражение ожидания, работающая задача приостанавливается, и цикл обработки событий выполняет следующую задачу».
Примечание. Я не ищу пример «asyncio.sleep(n)», я ищу «Когда задача выполняет выражение ожидания, работающая задача приостанавливается, а цикл событий выполняет следующую задачу». .... но это цель asyncio !
@D.L спасибо за комментарий. Да, я знаю, это цель asyncio, может быть, я не понимаю вывод. Я ожидаю вывод, например: "start_sum # первая задача ожидания ; start_mul # затем ожидание второй задачи ; end_sum # следующая задача первой очереди ; end_mul # Наконец следующая задача ожидания второй очереди ". Но этого не происходит, и я не понимаю, почему.
у вас есть три варианта cmmon: multiprocessing, threading и asyncio.... если вы хотите, чтобы они были независимыми, то это multiprocessing. Альтернативами являются threading и asyncio, которые похожи на потоки, управляемые пользователем. Так что это зависит от того, что вы хотите сделать ..... надеюсь, что это полезно.






Дело в том, что задачи возвращают управление циклу событий только с оператором yield. В вашем примере у вас уже есть три активных задачи (добавьте asyncio.all_tasks() в первую строку int_sum сопрограммы для подтверждения1), но, например, int_sum не сотрудничает. он не возвращает управление циклу событий. Почему ? Потому что у тебя нет yield.
Простое решение этой проблемы — изменить print_message на:
async def print_message(message):
print(message)
await asyncio.sleep(0)
если вы видите исходный код asyncio.sleep:
async def sleep(delay, result=None):
"""Coroutine that completes after a given time (in seconds)."""
if delay <= 0:
await __sleep0()
return result
...
А это тело __sleep0()(прямо над sleep):
@types.coroutine
def __sleep0():
"""Skip one event loop run cycle.
This is a private helper for 'asyncio.sleep()', used
when the 'delay' is set to 0. It uses a bare 'yield'
expression (which Task.__step knows how to handle)
instead of creating a Future object.
"""
yield
Теперь ваш вывод должен быть:
start_sum
start_mul
end_sum
end_mul
[7, 12]
1 Примечание: у вас есть три задачи, asyncio.gather сделает это за вас:
Если какой-либо ожидаемый в aws является сопрограммой, он автоматически запланирован как Задача.
Спасибо за ответ! Я сделал функцию "@types.coroutine; def next_task(): yield" и использовал ее в print_message просто для проверки. Но есть ли смысл сна или «следующей_задачи» в производственном коде? Знаете ли вы, что это плохая практика? Спасибо
@Rubén Нет Это не считается плохой практикой, когда вам нужно заставить асинхронную функцию передать управление циклу событий, это допустимый вариант. Но не создавайте себе дополнительный next_task, он вам просто не нужен, он уже определен в asyncio framework.
если вы хотите, чтобы задачи выполнялись параллельно, то вам нужно
multiprocessing, а неasyncio...