Асинхронный метод Python 2 Tornado - PullRequest
0 голосов
/ 13 января 2019

Я должен использовать Python 2 для выполнения асинхронных вызовов.

Я использую Торнадо для достижения этой цели, но если есть лучший инструмент, я могу поменять инструменты.

Следующий код выполняет мою sleep 2 && echo hi команду асинхронно в фоновом режиме

from tornado import gen
import subprocess
import time

@gen.coroutine
def longProcess():
    bashCommand = "sleep 5 && echo hi"
    process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
    output, error = process.communicate()

    yield output

futures = [longProcess() for x in range(0, 5)]

while True:
    if all(x.done() == True for x in futures):
        break
    time.sleep(1)

print('All futures resolved')

Проблема в том, что x.done() возвращает True для всех фьючерсов до завершения моей команды bash.

Как я могу превратить process.communicate() в будущее (только после того, как ключевое слово "hi" станет доступным), чтобы я мог дождаться завершения всех фьючерсов и получить, а затем получить выходные данные из фьючерсов?

1 Ответ

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

Используйте собственный класс Торнадо process.Subprocess, который является оберткой вокруг stdlib subprocess.Popen.

Пример:

from tornado import process

@gen.coroutine
def longProcess():
    bashCommand = "sleep 5 && echo hi"

    proc = process.Subprocess(bashCommand.split(), stdout=subprocess.PIPE)

    yield proc.wait_for_exit() # `wait_for_exit` returns a future 
                               # which you can yield. Basically, it means
                               # you can wait for the process to complete
                               # without blocking the server

    return proc.stdout.read() # return the result of the process

    # for Python 2:
    # you can't return from a generator
    # instead use this:
    # raise gen.Return(proc.stdout.read())

Вам не нужен цикл while. Вы можете переместить этот код в другую сопрограмму и получить список futures. Как это:

@gen.coroutine
def main():
    futures = [longProcess() for x in range(0, 5)]

    results = yield futures # this coroutine will not move further 
                            # until every future in the list 
                            # `futures` is resolved

    for result in results:
        print(result)

    print('All futures resolved')

В качестве примечания не используйте time.sleep. Это заблокирует весь сервер. Вместо этого используйте асинхронный эквивалент gen.sleep - yield gen.sleep(1)

...