如何将背景线程添加到烧瓶中?

Mar*_*nus 73 python rest flask

我正在忙着写一个小游戏服务器试用烧瓶.游戏通过REST向用户公开API.用户可以轻松执行操作和查询数据,但是我想在app.run()循环之外为"游戏世界"提供服务以更新游戏实体等.鉴于Flask实施得非常干净,我想要看看Flask是否有办法做到这一点.

小智 67

您的其他线程必须从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()          
Run Code Online (Sandbox Code Playgroud)

从Gunicorn中调用它是这样的:

gunicorn -b 0.0.0.0:5000 --log-config log.conf --pid=app.pid myfile:app
Run Code Online (Sandbox Code Playgroud)

  • 我发现使用flask的自动重载功能时会出现问题(每次重新加载都会创建一个新线程).为了解决这个问题,我使用[werkzeug.serving.is_running_from_reloader](http://werkzeug.pocoo.org/docs/0.10/serving/#werkzeug.serving.is_running_from_reloader)仅在应用程序未从重新加载器运行时创建它. (10认同)
  • @caio它应该是"with dataLock:"大写字母L以上. (2认同)
  • 这个例子有点令人困惑,因为创建的名为"yourThread"的对象不是一个线程.这是一个计时器:建议你重命名它.并且,当执行yourTimer时(在doStuff中),我不知道你的线程是否有效 - 即,你是否可以对尚未执行的Timer执行cancel.如果这可能是一个问题,它的效率问题是每次执行都会创建一个新对象. (2认同)

And*_*röm 10

除了使用纯线程或 Celery 队列(注意不再需要flask-celery),你还可以看看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()
Run Code Online (Sandbox Code Playgroud)