6

I have a simple bottle script that forwards button processes on a web page. Within the same script I was looking to have a continuous loop that among other tasks listened out for these button presses. I attempted to run the bottle script in a separate thread but it doesn't work as I expected.

Is there a better (or should I say correct) way to do this?

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内部定义的局部变量,method而不是全局可见和可修改的pushed变量。

您需要的是以下内容(但向下滚动以获得正确的解决方案):

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()使用超时而不是 nowait 版本可能会更好,以免线程无用地消耗 CPU。

此外,诸如启动线程的行和调用的行等代码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 回答