6

Web ページでボタン プロセスを転送する単純なボトル スクリプトがあります。同じスクリプト内で、他のタスクの中でこれらのボタンの押下をリッスンする連続ループを探していました。ボトル スクリプトを別のスレッドで実行しようとしましたが、期待どおりに動作しません。

これを行うためのより良い(または正しいと言うべき)方法はありますか?

from bottle import get, post, request, run, redirect
import threading

@get('/button')
def button():
    return '''
        <form action="/button" method="post">
            <input type="submit" value="Push" />
        </form>
    '''

@post('/button')
def action():
    print "button pushed"
    pushed = True
    redirect("/button")

#run(host='localhost', port=8080)
threading.Thread(target=run, kwargs=dict(host='localhost', port=8080)).start()


def method():
    pushed = False
    print "started"
    while 1:
        # do other stuff
        if pushed:
            print "push recieved"
            pushed = False

method()
4

1 に答える 1

12

グローバルに表示され、変更可能な変数ではなく、pushed内部で定義されたローカル変数のみが表示されるため、機能しません。methodpushed

代わりに必要なのは次のとおりです(ただし、正しい解決策については下にスクロールしてください):

pushed = False

@post('/button')
def action():
    global pushed  # needed because otherwise assigning to `pushed` will
                   # just create a local variable shadowing the global one
    pushed = True
    redirect("/button")

def method():
    # pushed = False   <----- this line is not needed, and if enabled, will, again, 
    #                         create a local variable shadowing the global one
    global pushed  # again, otherwise the `pushed = False` statement will create a local variable
    while True:  # use real booleans, i.e. True/False not 1/0
        if pushed:
            print "push recieved"
            pushed = False

method()

注:スニペット内に追加したコメントに注意してください。

しかし、グローバル変数 (または通常の変数) を介してスレッドと通信することは、他の複数のスレッドが同じ変数に同時にアクセス (読み取りまたは書き込み) する可能性があるため、悪い習慣です。代わりに、スレッド間でイベントを通知するには、キューを使用します。

from Queue import Queue, Empty

button_pressed = Queue()

@post('/button')
def action():
    button_pressed.put(1)  # can be any value really
    redirect("/button")

def method():
    while True:
        try:
            button_pressed.get_nowait()
        except Empty:
            # NOTE: if you don't do anything here, this thread
            # will consume a single CPU core
            pass
        else:
            print "push recieved"

get_nowait()何かがputキューに入っているかどうかを確認し、そうであればそれを返します。それ以外の場合は、すぐに が発生しEmptyます。ゼロ以外のタイムアウトを渡すことも、タイムアウトなしで呼び出すこともできます。この場合、キューで何かが利用可能になるまで待機します。

.get()スレッドが無駄に CPU を消費しないようにするには、nowait バージョンよりもタイムアウトを使用する方がよいでしょう。

さらに、スレッドを開始する行や呼び出す行などのコードはmethod()、モジュールの最上位スコープに直接配置しないでください。代わりに、次のように条件付きで呼び出します。

if __name__ == '__main__':
    threading.Thread(target=run, kwargs=dict(host='localhost', port=8080)).start()
    method()

このようにして、.pyファイルがモジュールとしてインポートされた場合ではなく、ファイルが直接実行された場合にのみコードが実行されます。また、通常どおり呼び出しrun()、代わりにmethodスレッド内に配置することを検討してください。

于 2013-10-26T08:37:13.073 に答える