플라스크에 배경 스레드를 추가하려면 어떻게해야합니까?


79

플라스크를 시험해보기 위해 작은 게임 서버를 작성 하느라 바쁘다. 이 게임은 REST를 통해 사용자에게 API를 노출합니다. 사용자가 작업을 수행하고 데이터를 쿼리하는 것은 쉽지만 app.run () 루프 외부에서 "게임 세계"를 서비스하여 게임 엔터티 등을 업데이트하고 싶습니다. Flask가 매우 깔끔하게 구현되어 있으므로 이 작업을 수행하는 Flask 방법이 있는지 확인합니다.


Flask-Admin과 같은 것을 의미합니까? 또는 ORM (SQL-Alchemy)을 사용하는 경우 응용 프로그램이 실행중인 경우에도 데이터베이스를 쿼리하는 새 db 세션을 만들 수 있습니다.
reptilicus

해커 같은 방법이있는 것 같지만 기술적으로 지원되지 않는다고 생각합니다. 나는 또한 이것을 위해 플라스크 셀러리를 사용하는 것에 대해 말하는 이 답변 을 찾았습니다 .
girasquid

실제로 많은 계산을 수행해야하는 경우 하위 프로세스 모듈을 사용하고 단순히 새 프로세스를 생성하여 추가 계산을 수행 할 수 있습니다.
Maus

@girasquid Agreed, celery 또는 다른 작업 대기열 시스템은 이런 종류의 작업에 이상적입니다. 일반적으로 스레드 또는 하위 프로세스에 대한 제어 권한이 적습니다 (예고없이 서버에서 상위 프로세스를 거둘 수 있기 때문입니다).
Sean Vieira 2013 년

이는 계획이지만 하위 프로세스는 노출 된 플라스크 API를 통해 액세스하고 설정하려는 데이터 구조를 조작합니다. 문제가 발생하지 않습니까?
Marinus

답변:


80

추가 스레드는 WSGI 서버에서 호출하는 동일한 앱에서 시작되어야합니다.

아래 예제는 5 초마다 실행되는 백그라운드 스레드를 생성하고 Flask 라우팅 함수에서도 사용할 수있는 데이터 구조를 조작합니다.

import threading
import atexit
from flask import Flask

POOL_TIME = 5 #Seconds

# variables that are accessible from anywhere
commonDataStruct = {}
# lock to control access to variable
dataLock = threading.Lock()
# thread handler
yourThread = threading.Thread()

def create_app():
    app = Flask(__name__)

    def interrupt():
        global yourThread
        yourThread.cancel()

    def doStuff():
        global commonDataStruct
        global yourThread
        with dataLock:
        # Do your stuff with commonDataStruct Here

        # Set the next thread to happen
        yourThread = threading.Timer(POOL_TIME, doStuff, ())
        yourThread.start()   

    def doStuffStart():
        # Do initialisation stuff here
        global yourThread
        # Create your thread
        yourThread = threading.Timer(POOL_TIME, doStuff, ())
        yourThread.start()

    # Initiate
    doStuffStart()
    # When you kill Flask (SIGTERM), clear the trigger for the next thread
    atexit.register(interrupt)
    return app

app = create_app()          

다음과 같이 Gunicorn에서 호출하십시오.

gunicorn -b 0.0.0.0:5000 --log-config log.conf --pid=app.pid myfile:app

14
플라스크의 자동 다시로드 기능을 사용할 때 이것이 문제가되는 것을 발견했습니다 (다시로드 할 때마다 새 스레드가 생성됨). 이 문제를 해결하기 위해 werkzeug.serving.is_running_from_reloader 를 사용 하여 앱이 리 로더에서 실행되지 않을 때만 생성했습니다.
raffomania 2015 년

2
@caio 위의 대문자 L은 "with dataLock :"이어야합니다.
Jesse Sanford

이것은 좋은 해결책입니다. 다중 처리 또는 스레딩 모듈을 사용하는 플라스크 앱을 처리하는 데 도움이됩니다. 나는 그것을 좋아한다.
Shan Valleru

2
이 예제는 "yourThread"라는 생성 된 객체가 스레드가 아니기 때문에 약간 혼란 스럽습니다. 타이머입니다. 이름을 변경해보세요. 그리고 yourTimer가 실행되면 (doStuff에서) yourThread가 유효한지 알 수 없습니다. 즉, 실행되지 않은 Timer에서 cancel을 실행할 수 있는지 여부를 알 수 없습니다. 문제가 될 수 있다면 실행마다 새 객체를 생성한다는 효율성 문제가 있습니다.
브라이언 Bulkowski

1
"() is_running_in_background"를 확인하기위한 올바른 문장은 이렇게 같다 : 수입 is_running_from_reloader을 werkzeug.serving에서 경우 is_running_from_reloader () == 거짓 : startBackground ()
브라이언 Bulkowski

7

순수 스레드 또는 셀러리 대기열 (플라스크 셀러리는 더 이상 필요하지 않음)을 사용하는 것 외에도 flask-apscheduler를 살펴볼 수도 있습니다.

https://github.com/viniciuschiele/flask-apscheduler

https://github.com/viniciuschiele/flask-apscheduler/blob/master/examples/jobs.py 에서 복사 한 간단한 예제 :

from flask import Flask
from flask_apscheduler import APScheduler


class Config(object):
    JOBS = [
        {
            'id': 'job1',
            'func': 'jobs:job1',
            'args': (1, 2),
            'trigger': 'interval',
            'seconds': 10
        }
    ]

    SCHEDULER_API_ENABLED = True


def job1(a, b):
    print(str(a) + ' ' + str(b))

if __name__ == '__main__':
    app = Flask(__name__)
    app.config.from_object(Config())

    scheduler = APScheduler()
    # it is also possible to enable the API directly
    # scheduler.api_enabled = True
    scheduler.init_app(app)
    scheduler.start()

    app.run()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.