[英]threading a bottle app
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()
It doesn't work because it's only seeing the local variable pushed
defined inside of method
as opposed to a globally visible and modifiable pushed
variable. 这是行不通的,因为它只能看到局部变量
pushed
的内部定义的method
,而不是一个全局可见,修改的pushed
变量。
What you need instead is the following (but scroll down for a correct solution): 您需要的是以下内容(但向下滚动以获得正确的解决方案):
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()
NOTE: pay attention to the comments I added inside of the snippet. 注意:请注意我在代码段中添加的注释。
BUT, it is bad practice to communicate with threads via global variables (or normal variables) because multiple other threads might be accessing (reading or writing) the same variable simultaneously. 但是,通过全局变量(或正常变量)与线程进行通信是不好的做法,因为多个其他线程可能同时访问(读取或写入)同一个变量。 Instead, to signal events between threads, use queues:
相反,要在线程之间发出事件信号,请使用队列:
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()
checks if something has been put
into the queue and if yes, returns it; get_nowait()
检查是否已将某些内容put
队列中,如果是,则返回它; otherwise it immediately raises Empty
. 否则它立即引发
Empty
。 You can also pass a non-zero timeout to it, or call it without a timeout, in which case it will wait until something is available in the queue. 您还可以向其传递非零超时,或者在没有超时的情况下调用它,在这种情况下,它将等待队列中的某些内容可用。
It's likely better to use .get()
with a timeout rather than the nowait version to not make the thread consume CPU uselessly. 最好使用带有超时的
.get()
而不是nowait版本,以免线程消耗CPU无用。
Furthermore , code such as the line where you start the thread as well as where you call method()
should not be put directly into the module top-level scope; 此外 ,诸如启动线程的行以及调用
method()
不应直接放入模块顶级作用域; instead, call them conditionally like this: 相反,像这样有条件地调用它们:
if __name__ == '__main__':
threading.Thread(target=run, kwargs=dict(host='localhost', port=8080)).start()
method()
this way that code will only execute if the .py
file is executed directly and not when it's imported as a module. 这样,代码只会在
.py
文件直接执行时执行,而不是在作为模块导入时执行。 Also, consider calling run()
normally and instead putting method
inside of a thread. 另外,考虑正常调用
run()
,而不是将method
放入线程中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.