穿线瓶应用程序

时间:2013-10-26 08:32:25

标签: python multithreading bottle

我有一个简单的瓶子脚本,可以转发网页上的按钮流程。在同一个脚本中,我希望有一个连续的循环,其他任务听取了这些按钮按下。我试图在一个单独的线程中运行瓶子脚本,但它不能像我预期的那样工作。

有没有更好的(或我应该说是正确的)这样做的方式?

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()

1 个答案:

答案 0 :(得分:11)

它不起作用,因为它只看到pushed内部定义的局部变量method,而不是全局可见且可修改的pushed变量。< / p>

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

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放在线程中。