2013-01-17 28 views
49

私はフラスコを試すための小さなゲームサーバーを書くのに忙しいです。ゲームは、RESTを介してユーザーにAPIを公開します。ユーザーがアクションやクエリデータを簡単に実行することは簡単ですが、app.run()ループの外側で "ゲームの世界"にサービスを提供して、ゲームエンティティなどを更新したいと考えています.Flaskがきれいに実装されていることを考えれば、これを行うフラスコの方法があるかどうかを調べる。フラスコにバックグラウンドスレッドを追加するにはどうすればよいですか?

+0

Flask-Adminのような意味ですか?または、ORM(SQL-Alchemy)を使用している場合は、アプリケーションが実行中であってもデータベースを照会するための新しいdbセッションを作成することができます。 – reptilicus

+0

実際に多くの計算を行う必要がある場合は、サブプロセスモジュールを使用し、追加の計算を行うために単に新しいプロセスを生成することができます。 – Maus

+0

これは計画ですが、サブプロセスはデータ構造を操作し、エクスポーズしたフラスコAPIを介してアクセスして設定したいと考えています。私は問題に遭遇しませんか? – Marinus

答えて

43

追加のスレッドは、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 
+6

フラスコの自動リロード機能を使用するときに問題があることがわかりました(リロードするたびに新しいスレッドが作成されています)。これを修正するため、私は[werkzeug.serving.is_running_from_reloader](http://werkzeug.pocoo.org/docs/0.10/serving/#werkzeug.serving.is_running_from_reloader)を使用して、アプリケーションがリローダから実行されていないときにのみ作成しました。 – raffomania

+2

@caioこれは上記の "dataLock:"の大文字Lでなければなりません。 –

+0

これは素晴らしい解決策です。マルチプロセッシングやスレッドモジュールを使用するフラスコアプリを扱うのに役立ちます。私はそれが好きです。 –

3

a hackish way to do itのようですが、これは技術的にはサポートされていないと思います。

this answerも見つかりました。これについてはフラスコセロリーを使用しています。

+1

+1 - セロリなどのタスクキューシステムは、この種の処理には理想的です。スレッドやサブプロセスを制御することはほとんどありません(親プロセスは予告なしにサーバーによって刈り取られる可能性があります)。 –

2

フラスコ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() 
関連する問題