简体   繁体   中英

How can I run bottle concurrently with an infinite loop?

I am trying to run bottle.py as a process inside a script but I am frustrated because it doesn't work as I expected. Here is a hypothetical/shortened representation of my script. I tried to add as much comments as I could.

magball.py

import serial
from bottle import route, run, template, request
import multiprocessing
import logging
import datetime


#Here are the most important variables which will be used in the entire script
global lastcommand #The last command received from bottle web interface
global status #What is the current status

lastcommand = 'Go Home' #Options: Start Drawing, Go Home, Next Drawing
status = 'home' #Options: home, homing (means going home), drawing

def log_this(level, msg)
    #a special log function based on logging library for debugging
    pass # <- details are not important, it is working fine

now = datetime.datetime.now()
timeString = now.strftime("%Y-%m-%d %H:%M")
info = {'title' : 'MAGBALL', 'time': timeString, 'lastcommand': lastcommand, 'status': status} #These are passed to main.tpl
@route('/', method='GET')
@route('/', method='POST')
def index(): #<- This works fine, passing the info to the template file (main.tpl) in views directory
    global lastcommand #<- Isn't this referring to the global lastcommand declared at the beginning?
    if request.method == 'POST':
        lastcommand = request.forms.get("submit") #<- This works fine and lastcommand changes when the button on the web page is clicked    
        log_this('info', (lastcommand + ' clicked on web interface')) #<- I can see in the logs which button is clicked, so, this should mean 
                                                                      #that lastcommand (supposedly the global one) was changed successfully

    return template('main.tpl', info)

p_bottle = multiprocessing.Process(target=run, kwargs=dict(host='0.0.0.0', port=80, debug='True')) #<- I start bottle as a process because I think I have to
p_bottle.daemon = True

def draw_pattern() #<- This function can easily run for hours which is fine/normal for the purpose
                   #Unless lastcommand is not equal to 'Start Drawing' this should run forever
    global status
    global lastcommand
    status = 'drawing' #<- I think this should also refer to the global lastcommand declared at the beginning
    #Opens a random file from a specific directory, 
    for filename in shuffled_directory:
        #reads the file line by line and feeds it to the serial port
        .
        .
        if lastcommand != 'Start Drawing': #<- This never works! Although I see in the logs that lastcommand was changed by index() function
            log_this('warning', 'Last command changed during line feeding.')
            break

def go_home()
    global status
    status = 'homing' #<- I think this should also refer to the global lastcommand declared at the beginning
    #Send some commands to serial port and after that change the value of status
    .
    .
    status = 'home'

while true: #This is the infinite loop that needs to run forever
    global status #Don't these variables also refer to the global variables declared at the beginning? 
    global lastcommand
    p_bottle.start() #The bottle.py web interface runs successfully
    #The following while, if etc never runs. I think this "while true:" statement never gets notified
    #that the values of lastcommand and/or status has changed
    while lastcommand == 'Start Drawing':   
        if status == 'home':
            draw_pattern()
        if status == 'homing':
            time.sleep(5)
        if status == 'drawing':
            pass
    while lastcommand == 'Next Drawing':
        if status == 'home':
            draw_pattern()
        if status == 'homing':
            time.sleep(5)
        if status == 'drawing':
            go_home()
            draw_pattern()
    while lastcommand == 'Go Home':
        if status == 'home':
            pass
        if status == 'homing':
            pass
        if status == 'drawing':
            go_home()

main.tpl

<!DOCTYPE html>
   <head>
      <title>{{ title }}</title>
   </head>
   <body>
      <h1>Magball Web Interface</h1>
      <h2>The date and time on the server is: {{ time }}</h2>
    <h2>The last command is: {{ lastcommand }}</h2>
    <h2>Status: {{ status }}</h2>
    <form name='magballaction' method='POST'>
    <input type="submit" name="submit" value="Start Drawing">
    <input type="submit" name="submit" value="Go Home">
    <input type="submit" name="submit" value="Next Drawing">
    </form>
   </body>
</html>

And here is what happens:
The bottle process runs fine (the web page is accesible) and when I click the buttons on the web page, I see in the logs that the value of lastcommand was changed by web interface.

However the infinite loop at the end ( while true: ) never gets notified that the value of lastcommand was changed. So forexample, if the status = home and lastcommand was changed to 'Start Drawing' from the web interface, it does not perform draw_pattern() . It does nothing.

I tried to put everything inside the def index() function before the return template('main.tpl', info) line but then the codes run however the web interface waits for the code to complete in order to start. Since draw_pattern() lasts for hours, the return template('main.tpl', info) line practically does not run and the web page is not accessible.

I also tried to run def index() as a normal function, but when I do so, the only thing that runs is the web inteface ( def index() ).

So, what can I do to notify the while loop that the value of lastcommand and/or status has changed?

For anyone who is interested I have solved the problem using threading instead of multiprocessing. So instead of using this:

p_bottle = multiprocessing.Process(target=run, kwargs=dict(host='0.0.0.0', port=80, debug='True')) 
p_bottle.daemon = True

I used:

p_bottle = threading.Thread(target=run, kwargs=dict(host='0.0.0.0', port=80, debug='True'))
p_bottle.daemon = True

and now the function in the thread can change the global variable successfully which is instantly picked up by the infinite while true loop. Thanks everyone for suggestions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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