我有一个简单的瓶子脚本,可以转发网页上的按钮流程。在同一个脚本中,我希望有一个连续的循环,其他任务听取了这些按钮按下。我试图在一个单独的线程中运行瓶子脚本,但它不能像我预期的那样工作。
有没有更好的(或我应该说是正确的)这样做的方式?
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()
答案 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
放在线程中。