简体   繁体   English

穿线瓶应用程序

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM