run_in_executor
разработан для использования в asyncio , поэтому его возвращаемое значение - asyncio Future
, которым манипулирует поток, выполняющий цикл событий asyncio. Поскольку ваш код вращается в цикле while
, ничего не ожидая, он не дает возможности циклу событий вообще запускаться, эффективно блокируя цикл событий. Будущее остается "ожидающим", потому что обратный вызов, который должен был бы обновиться, должен вызываться циклом событий, который в настоящее время не работает - он просто находится в очереди.
Замена time.sleep(0.1)
на await asyncio.sleep(0.1)
, вероятно, решит проблему. Но тогда вам вообще не нужен цикл while
; поскольку будущее асинхронно ожидаемо, вы можете await
напрямую:
await future
# Do some stuff, with the future done.
await
приостанавливает текущую сопрограмму до тех пор, пока не завершится будущее, предоставляя другим задачам возможность выполнить в это время. Возвращает значение будущего или распространяет исключение.
Альтернатива - вообще не использовать asyncio, а использовать concurrent.futures
напрямую. Таким образом вы получите ожидаемую семантику потоков (истинное «фоновое» выполнение) и Future
, который работает соответственно.
# keep this in a global variable, so that the same executor
# is reused for multiple calls
executor = concurrent.futures.ThreadPoolExecutor()
# later, submit foo to be executed in the background
future = executor.submit(foo)
Это будущее concurrent.futures
будущее , которое поддерживает ожидание такого результата:
result = future.result()
Кроме того, с таким будущим ваш оригинальный код будет работать без изменений.