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