Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/350.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何将背景线添加到烧瓶?_Python_Rest_Flask - Fatal编程技术网

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

Python 如何将背景线添加到烧瓶?,python,rest,flask,Python,Rest,Flask,我正忙着写一个小游戏服务器来试用flask。游戏通过REST向用户公开API。用户很容易执行操作和查询数据,但是我想在app.run()循环之外为“游戏世界”提供服务,以更新游戏实体等。鉴于Flask的实现非常干净,我想看看是否有办法做到这一点。您的附加线程必须从WSGI服务器调用的同一个应用程序启动 下面的示例创建了一个后台线程,该线程每5秒执行一次,并处理同样可用于路由函数的数据结构 import threading import atexit from flask import Flask

我正忙着写一个小游戏服务器来试用flask。游戏通过REST向用户公开API。用户很容易执行操作和查询数据,但是我想在app.run()循环之外为“游戏世界”提供服务,以更新游戏实体等。鉴于Flask的实现非常干净,我想看看是否有办法做到这一点。

您的附加线程必须从WSGI服务器调用的同一个应用程序启动

下面的示例创建了一个后台线程,该线程每5秒执行一次,并处理同样可用于路由函数的数据结构

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

除了使用纯线程或芹菜队列(请注意,不再需要flask芹菜),还可以查看flask apscheduler:

下面是一个简单的例子:


首先,您应该使用任何WebSocket或轮询机制将发生的更改通知前端部件。我使用
Flask-SocketIO
wrapper,非常喜欢为我的小应用程序提供异步消息

嵌套时,您可以在单独的线程中执行所需的所有逻辑,并通过
SocketIO
对象通知前端(Flask保持与每个前端客户端的连续开放连接)

例如,我刚刚在后端文件修改中实现了页面重新加载:

<!doctype html>
<script>
    sio = io()

    sio.on('reload',(info)=>{
        console.log(['sio','reload',info])
        document.location.reload()
    })
</script>

你是说像烧瓶管理员?或者,如果您使用的是ORM(SQL Alchemy),那么即使应用程序正在运行,您也可以创建一个新的db会话来查询数据库。我还发现了,其中谈到了使用flask芹菜。如果您确实需要进行大量计算,您可能希望使用子流程模块,并简单地生成新流程来进行额外计算。@girasquid同意,芹菜或其他一些任务队列系统是这类事情的理想选择-您通常对线程或子进程的控制较少(因为服务器可能会在不通知的情况下获取父进程)。这是一个计划,但是子进程将操纵数据结构,您希望通过公开的flask api访问和设置这些数据结构。我会不会遇到问题?在使用flask的自动重新加载功能(每次重新加载时都会创建一个新线程)时,我发现这是个问题。为了解决这个问题,我以前只在应用程序没有从重新加载程序运行时创建它。@caio它应该是“with dataLock:”上面大写L。这是一个很好的解决方案;帮助处理使用多处理或线程模块的flask应用程序。我喜欢。这个例子有点混乱,因为创建的名为“yourThread”的对象不是线程。这是计时器:建议您重命名它。而且,当您的计时器被执行时(在doStuff中),我不知道您的线程是否有效——也就是说,您是否可以对尚未执行的计时器执行cancel。它的效率问题是每次执行时都会创建一个新对象,如果这可能是一个问题的话。检查“is_running_in_background()”的正确语句如下:from werkzeug.service import is_running_from_reloader if is_running_from_reloader()==False:startBackground()
<!doctype html>
<script>
    sio = io()

    sio.on('reload',(info)=>{
        console.log(['sio','reload',info])
        document.location.reload()
    })
</script>
class App(Web, Module):

    def __init__(self, V):
        ## flask module instance
        self.flask = flask
        ## wrapped application instance
        self.app = flask.Flask(self.value)
        self.app.config['SECRET_KEY'] = config.SECRET_KEY
        ## `flask-socketio`
        self.sio = SocketIO(self.app)
        self.watchfiles()

    ## inotify reload files after change via `sio(reload)``
    def watchfiles(self):
        from watchdog.observers import Observer
        from watchdog.events import FileSystemEventHandler
        class Handler(FileSystemEventHandler):
            def __init__(self,sio):
                super().__init__()
                self.sio = sio
            def on_modified(self, event):
                print([self.on_modified,self,event])
                self.sio.emit('reload',[event.src_path,event.event_type,event.is_directory])
        self.observer = Observer()
        self.observer.schedule(Handler(self.sio),path='static',recursive=True)
        self.observer.schedule(Handler(self.sio),path='templates',recursive=True)
        self.observer.start()