Asyncio, чтобы получить статус долгосрочного кода - PullRequest
0 голосов
/ 30 января 2019

У меня есть код, который будет работать на сервере.Это может занять много времени (минимум минут).Я хочу иметь возможность опрашивать сервер, где в коде это в настоящее время.Я думал, что мог бы использовать asyncio, но похоже, что это не то, что мне нужно.

Вот некоторый код, который я написал, чтобы протестировать его (сохраненный как test_async.py):

import asyncio
import time

the_status = 'idle'


async def waiting():
    global the_status
    await asyncio.sleep(0.001)
    the_status = 'running'
    time.sleep(30)
    the_status = 'finished'


def get_status():
    global the_status
    return the_status


async def main():
    loop.create_task(waiting())


loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

Я запускаю его, открыв консоль Python и введя:

from test_async import *

Я ожидал, что он начнет работать waiting(), изменит the_status на «работа», а затем подождет 30 секунд, прежде чем перевести состояние в «готово».В то же время, я должен получить консольную подсказку обратно, и я смог бы получить текущее состояние, набрав get_status().

На самом деле происходит то, что переменная the_status никогда не меняется от своего первоначальногосостояние «простоя».

Я что-то не так делаю?Разве asyncio не является ответом на то, что я пытаюсь сделать?

Моя версия Python - 3.6.

1 Ответ

0 голосов
/ 31 января 2019

Я делаю что-то не так?

Код имеет две проблемы:

  • main просто создает задачу, не ожидая ее -вы можете думать о create_task как о создании «фоновой» задачи.Но в асинхронных фоновых задачах выполняется только столько времени, сколько работает основной цикл, поэтому run_until_complete(main()) завершается немедленно, потому что main() возвращается сразу после создания задачи.При остановке основного цикла задача waiting не может начать выполнение.

  • waiting вызывает time.sleep, что не разрешено в асинхронном режиме.Asyncio - это кооперативная многозадачная система для обратных вызовов и сопрограмм в стиле JS, которые приостанавливаются, когда ожидают чего-то, что блокирует.time.sleep не приостанавливается, он просто блокирует весь поток цикла событий.Выполнение устаревшего кода блокировки внутри asyncio правильно выполняется с помощью run_in_executor.

Является ли asyncio ответом на то, что я пытаюсь сделать?

Если у вас есть какой-то код блокировки, который нужно выполнить «в фоновом режиме», вам следует использовать потоки.

import time, concurrent.futures

the_status = 'idle'

def waiting():
    global the_status
    time.sleep(0.001)
    the_status = 'running'
    time.sleep(30)
    the_status = 'finished'

executor = concurrent.futures.ThreadPoolExecutor()
executor.submit(waiting)

Импорт кода работает должным образом:

>>> import thr2
>>> thr2.the_status
'running'
...