1

I wrote a Python script that executes an optimization and runs days to get a solution (due to the costly objective function). In all days work it will be sufficient to just stop the calculation at some point because the solution is good enough for me (but not for the optimization algorithm).

The problem is, I can always abort hitting Ctrl+C. But then there is no chance to nicely output the current best parameters, plot the data, save it etc. It would be great to stop the script in a controlled way after the next calculation of the objective function. So my thought was so question some variable (if user_stop=True) and programatically stop the optimization. But how to set such a variable? The python console is blocked during execution.

I thought about setting the content of a text file and reading it in each iteration but it's more than poor and hard to explain for other users of the script. Theoretically, I could also ask the user for an input but than the script won't run automatically (which it should until someone decides to stop).

Any ideas for my problem?

Basically that's it - stop the loop at some point but execute the print:

a = 0
while True:
    a = a + 1
print(a)
  • Inserting or altering a variable inside a running process is highly insecure, and quite difficult. Debuggers do it, and that's the route you would have to take (in older versions of Windows DLL inoculation could be done, but that's problematic on recent versions). Which operating system are you running on? – cdarke Jul 05 '16 at 06:58
  • 2
    Look into `signals` module. You can send in a signal from outside the process, your process with catch it and may be write all your parameters to your file before calling `sys.exit(..)`. – UltraInstinct Jul 05 '16 at 07:03
  • I am running on Windows 7. I looked into the signals module and it seems to induce more trouble than solutions on Windows according to a lot of threads here. I fear this will not be my preferred solution. However, if no other ones appear I will give it a try. – monoceros84 Jul 05 '16 at 10:02

3 Answers3

0

maybe you can use a do-while loop. holding your target in a varible outside the loop and start looping the calculatio while <= your target calculation.

Asfbar
  • 259
  • 6
  • 21
0

For Windows, I would use msvcrt.getch()

For example, this script will loop until a key is pressed, then, if it is q, prompt for the user to quit: (Note that the if statement uses 'short circuiting' to only evaluate the getch() - which is blocking - when we know that a key has been pressed.)

import msvcrt, time

while True: #This is your optimization loop
    if msvcrt.kbhit() and msvcrt.getch() == 'q':
        retval = raw_input('Quit? (Y/N) >')
        if retval.lower() == 'y':
            print 'Quitting'
            break #Or set a flag...
    else:
        time.sleep(1)
        print('Processing...')

If you place this if block at a point in the optimization loop where it will be frequently run, it will allow you to sop at a convenient point, or at least set a flag which you can check for at the end of each optimization run.

If you cannot place it somewhere where it will be frequently checked, then you can look at handling the KeyboardInterrupt raised by Ctrl-C

If you are running on Linux, or need cross-platform capability, have a look at this answer for getting the keypress.

Community
  • 1
  • 1
SiHa
  • 7,830
  • 13
  • 34
  • 43
  • This would be a wonderful solution, I really like it. However, nothing happens when I hit any keys. msvcrt.kbhit() always returns False, no matter where the window focus lies.I am running in Windows 7, Anaconda+IPython... Maybe the latter is the problem - but then: is there a way this still works? – monoceros84 Jul 05 '16 at 08:07
  • Odd. It could be Anaconda / IPython, I suppose. [here](ithub.com/ContinuumIO/anaconda-issues/issues/202) is a post mentioning that Anaconda only ships with an old version of the DLL, but I wouldn't have thought that would be a problem. To be clear - the above code run as a standalone script doesn't work? (works on my Win 7 machine) – SiHa Jul 05 '16 at 08:22
  • It works in the command line with python and with ipython. But unfortunately not within Anaconda. – monoceros84 Jul 05 '16 at 08:25
  • That's a shame. In that case, your best bet is to look at handling the CTRL-C, or the signals module as SuperSaiyan suggests above. – SiHa Jul 05 '16 at 08:33
0

If you poll your "variable" infrequently (say at most once every 20 seconds) then the overhead of testing for a file is negligible. Something like

import os
QUITFILE = "/home/myscript/quit_now.txt"
# and for convenience, delete any old QUITFILE that may exist at init time

...  # days later 
if os.path.isfile( QUITFILE) 
    # tidy up, delete QUITFILE, and exit

Then just echo please > home/myscript/quit_now.txt to tell your program to exit.

nigel222
  • 7,582
  • 1
  • 14
  • 22
  • Yeah, that's the solution I was thinking of already. However, when handing over the script to colleques it would be better to say "hit q or Esc to stop" than "create a file quit_now.txt in this specific folder"... ;) – monoceros84 Jul 05 '16 at 09:59
  • Well then, cheat. Detach the script (linux `command &`) and leave your colleague's terminal connected to a different program that will detect `q` or whatever and create `quit_now.txt` when it does. Not sure of the Windows equivalent, but there must be one. – nigel222 Jul 05 '16 at 10:12
  • Nice idea! That will prob. be the thing to do for the moment. – monoceros84 Jul 05 '16 at 11:20