Неблокирующее чтение из stdout в greenlet - PullRequest
1 голос
/ 12 января 2020

У меня есть приложение flask с SocketIO. В связи с этим я решил запустить приложение, используя библиотеку eventlet. Под капотом eventlet используется зеленые потоки для достижения параллелизма, если я не ошибаюсь.

В моем приложении я хочу порождать процесс и передавать вывод через веб-сокеты. Ниже приведен игрушечный пример

# eventlet==0.25.1
# flask==1.1.1
# flask-socketio==4.2.1

import eventlet
import subprocess
from flask import Flask, jsonify
from flask_socketio import SocketIO

app = Flask(__name__)
socketio = SocketIO(app)
socketio.init_app(app, cors_allowed_origins='*')

@app.route('/ping')
def start_ping():
    eventlet.spawn_n(ping)
    return jsonify(success=True)


@app.route('/hello')
def hello():
    return jsonify(data='Hello World')


def ping():
    proc = subprocess.Popen(
        ('ping', '-t', 'google.com'),
        stdout=subprocess.PIPE,
    )
    for line in proc.stdout:
        eventlet.sleep(0.5)
        socketio.emit('log_receive', str(line))


if __name__ == '__main__':
    socketio.run(app)
  1. Пользователь достигает конечной точки /ping.
  2. Функция ping() выполняется в зеленом потоке, который запускает команду ping у дочернего элемента строки процесса
  3. считываются из стандартного вывода подпроцесса, а emited через веб-сокеты
  4. eventlet.sleep(0.5) используется для обеспечения возможности запуска других частей приложения.

Вопрос:

for line in proc.stdout: блокируется. До тех пор, пока что-то не пройдет через стандартный вывод, eventlet.sleep(0.5) не будет выполняться, и, следовательно, остальной части приложения не будет предоставлена ​​возможность запуска. Таким образом, рендеринг приложения, не отвечает.

Я натолкнулся на этот вопрос о том, как выполнять неблокирующее чтение из subprocess.PIPE, и предлагается по существу использовать отдельный поток для чтения.

К сожалению, я не могу использовать отдельный поток из-за модели параллельного / сопрограммного программирования, которой я ограничен из-за eventlet / greenlet.

Я мог бы использовать fcntl () для выполнения неблокирующих операций чтения, но я на windows, и поэтому это не вариант

Что является альтернативой избегайте того, чтобы приложение находилось во власти подпроцесса stdout

...