Czytam o tym od kilku dni, z dokumentacji Flaska, starych postów przepełnienia stosu i Google. Znalazłem wiele tematów dotyczących flask.g i app.context () . Nie udało mi się zrozumieć, czuję się kompletnie ignorantem i zrezygnowałem ze zrozumienia tego, co się dzieje. więc potrzebuję tylko najprostszego sposobu, aby lokalna zmienna wewnątrz funkcji aplikacji kolby była kontrolowana i dostępna z innej funkcji kolby.

Krótko mówiąc, mam dwie funkcje w mojej aplikacji flask, jedną do przetwarzania danych (długie przetwarzanie), a drugą do zabijania przetwarzania przez zakończenie obiektu. Funkcja zabijania jest wywoływana przez adres url „mywebsite / kill”. Próbowałem uczynić obiekt globalnym, dodając „globalny” do zmiennej x (global x) i działało dobrze, z wyjątkiem tego, że obiekt został współużytkowany przez wszystkie żądania Flask, co zepsuło funkcję wielowątkowości Flask.

Dlatego muszę udostępnić x funkcji kill () i jednocześnie unikać używania normalnego global.

Dziękuję za pomoc przy pseudokodzie poniżej i nie kopiuj wklejania do słynnej dokumentacji kolby Hieroglifów.

Pseudo Przykład:

app = Flask(__name__)

@app.route("/process")
def process():
    x= process_obj()    #Long Processing
    return render_template('result.html')

@app.route("/kill")
def kill():
    x.close()
0
Mahmoud Bassyouni 20 listopad 2019, 02:34

1 odpowiedź

Zanim przejdziemy do Flask i udostępnimy, zobaczmy, co chcesz zrobić od czysto programistycznej strony rzeczy. Chcesz udostępnić zmienną między dwiema funkcjami.

Jest na to wiele sposobów. Jednym z nich jest użycie globals, którego wypróbowałeś i odkryłeś, że nie jest rozwiązaniem. Inne sposoby, które przychodzą mi do głowy to:

  1. Hermetyzacja powiązanych funkcji za pomocą klasy
  2. Przekazywanie udostępnionych informacji jako argumentu do innej funkcji
  3. Utrzymywanie rejestratora do przechowywania i pobierania do woli

1. Enkapsulacja za pomocą klas

Ponieważ Flask został zaprojektowany tak, aby był prosty i używa funkcji obywateli pierwszej klasy do tworzenia widoków, enkapsulacja przy użyciu klas pokonałaby cel. Właściwą alternatywą jest użycie Flask Blueprints do grupowania funkcji, które współdzielą wspólne dane. Oznaczałoby to użycie globalnych w module projektu i napotkalibyśmy ten sam problem, co w przypadku globals

2. Przekazywanie wartości jako argumentu

To prosty sposób na dzielenie się wartościami w normalnej sytuacji. W takim przypadku każda funkcja powiązana z adresem URL jako widok może, ale nie musi działać, w zależności od możliwości śledzenia obiektu procesu x. Załóżmy, że masz funkcję get_process(process_id), wtedy możesz zrobić coś takiego:

@app.route("/process")
def process():
    x = process_obj()
    return render_template('result.html', x=x)

W swoim szablonie wyrenderuj link jako:

<a href="{% url_for('kill', id=x.id) %}">Kill Process</a>

Następnie uzyskaj wartość w widoku zabijania w ten sposób:

@app.route("/kill")
def kill():
    id = request.args.get("id", None)
    if not id:
        abort(400)
    x = get_process(id)
    x.close()

Uwaga: jeśli ten proces, o którym mówisz w pseudokodzie, jest zarządzany przez menedżera zadań, takiego jak Celery lub Python-RQ, powyższe rozwiązanie powinno działać, ponieważ zawiera sposoby pobierania zadań na podstawie ich identyfikatora .

3. Utrzymywanie rejestratora

W przypadku, gdy nie używasz menedżera zadań i nie wykonujesz czegoś takiego jak wieloprocesorowość lub jakąś formę procesu aysnc w tle, to ten system musi mieć rejestratora, który pozwoli ci śledzić i pobierać uruchamiane procesy.

Sugerowałbym, aby tego nie robić i wybrać dobrze przetestowaną bibliotekę, taką jak Celery, Python RQ, Huey..etc., aby zrobić to za Ciebie.

Aktualizacja: Aby utworzyć rejestratora zasobów, utwórz klasę ze wzorcem singleton, do którego można uzyskać dostęp w całej aplikacji. Ponieważ używasz Flask, sugerowałbym, aby zostało to utworzone jako rozszerzenie Flask, dzięki czemu możesz udostępniać je wraz z aplikacją i używać kontekstu aplikacji, gdy jest to wymagane.

Poniższy pseudokod powinien Ci pomóc:

# import your necessary ssh library objects if required
from flask import current_app, _app_ctx_stack


class MyObjectRegistrar(object):
    def __init__(self, app=None):
        self.app = app
        self.my_objects = {}
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        # load any config into your registrar from the app config if necessary

    def add(self, id, obj):
        self.my_objects[id] = obj

    def get(self, id):
        return self.my_objects.get(id, None)

    def remove(self, id):
        del self.my_objects[id]

Z powyższym rejestratorem załadowanym jako rozszerzenie Flask:

from flask import Flask
from my_registrar import MyObjectRegistrar

app = Flask(__name__)
registrar = MyObjectRegistrar(app)

Dzięki temu uzyskasz obiekt rejestratora, którego możesz użyć w swoich widokach, takich jak:

@app.route("/process")
def process():
    obj = process_obj()
    registrar.add("some-unique-id", obj)
    return render_template("results.html", id="some-unique-id")

@app.route("/kill")
def kill():
    id = request.args.get("id")
    x = registrar.get(id)
    x.close()
    registrar.remove(id)
    return render_template("killed.html")

Uwaga: nie jest obowiązkowe, aby było to rozszerzenie Flask. Jeśli nie widzisz żadnego pożytku z posiadania obiektu Flask App, możesz po prostu zrobić klasę singletona w zwykłym module Pythona.

2
Arunmozhi 21 listopad 2019, 07:35
Dzięki Arunmozhi za komentarz, nie miałem jednak na myśli niczego związanego z procesami Menedżera zadań. "process_obj()", jest to funkcja związana z biblioteką połączeń SSH, której używam do łączenia i kontrolowania rzeczywistych urządzeń sieciowych. Właśnie użyłem nazwy procesu, ponieważ funkcja wymaga długiego czasu przetwarzania, aby połączyć, zebrać i przetworzyć dane. Masz więcej informacji na temat trzeciej opcji? wydaje się, że jest to najbliższe rozwiązanie.
 – 
Mahmoud Bassyouni
20 listopad 2019, 12:01
Dodałem aktualizację z pseudokodem, aby pomóc Ci zacząć. W razie potrzeby sprawdź rozwój rozszerzenia Flask flask.palletsprojects.com/en/1.1.x/ extensiondev.
 – 
Arunmozhi
21 listopad 2019, 07:36