Flask socketio многопоточный словарь дампа в очередь и отправить клиентам - PullRequest
0 голосов
/ 08 октября 2019

Цель состоит в том, чтобы просто создать очередь словарей и сообщить о ней клиенту.

РЕДАКТИРОВАТЬ Это отличается от Метания колб, работающего вне контекста запроса. 'при запуске подпотока потому что:

Это не делается в функции маршрута, это делается в socketio.start_background_task

Единственный код socketio имеет место в контексте с сокетом.emit мы отправляем словарь.

Стратегия: на стороне сервера необходимо выполнить 2 разных такта для каждого потока сборки, а затем в другом потоке socketio собрать результаты, которые находятся в поточной безопасной очереди FIFOсловари.

Затем отправьте эти словари клиенту и дождитесь каждого подтверждения.

Итак, теперь проблема решена: RuntimeError: Working outside of request context.

from flask import Flask, flash, request, redirect, render_template, Response, escape, jsonify, url_for, session, copy_current_request_context
#socketio
from flask_socketio import SocketIO, send, emit, join_room, leave_room, close_room, rooms, disconnect
import threading
from threading import Thread, Event, Lock
import queue
import random

def ack(value):
    if value != 'pong':
        logger.info('unexpected return value')

def fn_i():
    global q
    while True:
        time.sleep(1)
        q.put({'key_i':random.random()})
        return q

def fn_ii():
    global q
    while True:
        time.sleep(10)
        q.put({'key_ii':random.random()})
        return q

app = Flask(__name__)
socketio = SocketIO(app, async_mode=async_mode)
thread1=None
thread2=None
collector_thread=None
q = queue.Queue()
thread_lock = Lock()

def background_thread_collector():
    global thread1
    global thread2
    global q

    thread1 = threading.Thread(target=fn_i)
    thread1.start() 

    thread2 = threading.Thread(target=fn_ii)
    thread2.start() 

    """Example of how to send server generated events to clients."""
    while True:
        time.sleep(0.2)
        while not q.empty():
            socketio.emit('my_response',
                          q.get(), #{'data': 'Server generated event', 'count': count},
                          namespace='/test',
                          broadcast=True,
                          callback=ack
                         )

@app.route('/')
def index():
    return render_template('index.html', async_mode=socketio.async_mode)

@socketio.on('connect', namespace='/test')
def test_connect():
    global collector_thread
    logger.info(' Client connected ' + request.sid)
    with thread_lock:
        if collector_thread is None:
            collector_thread = socketio.start_background_task(background_thread_collector)            
    emit('my_response', {'data': 'Connected', 'count': 0})
if __name__ == '__main__':
    socketio.run(app, 
                host='localhost',
                 port=10000, 
                 debug=False) #True sends some exceptions and stops)

Приветствия

Ответы [ 2 ]

0 голосов
/ 11 октября 2019

Использование потоков с Flasksocketio непросто, поскольку требует, помимо прочего, обработки контекста приложений, чтобы обновить файл журнала сервера на стороне клиента, так как в этом случае проще использовать javascript, и файл можно обновить. соответственно. Даже прежний код с предлагаемыми изменениями не работал из-за контекста приложений, и, тем не менее, существует множество блогов или стековерсалов, подходы к которым ни в одном из них не нашли полного рабочего решения, кроме реализации как объяснение, потому что любой другой ответ требует полного работающего кода, и, следовательно,так как в состоянии реализовать здесь, учитывая, что это принятый ответ, ура.

0 голосов
/ 10 октября 2019

Это должно быть лучше обработано Flask-SocketIO, но проблема в том, что вы пытаетесь использовать обратный вызов для emit, который настроен на вещание всем клиентам:

            socketio.emit('my_response',
                          q.get(), #{'data': 'Server generated event', 'count': count},
                          namespace='/test',
                          broadcast=True,
                          callback=ack
                         )

Удалите обратный вызов иэмиттер должен работать просто отлично.

...