5

In my code I have a "while True:" loop that needs to run for a varying amount of time while collecting live data (3-5 hours). Since the time is not predetermined I need to manually end the while loop without terminating the script, so that it may continue to the next body of code in the script.

I do not want to use "input()" at the end of the loop, because then I have to manually tell it to continue looping every time it finishes the loop, I am collecting live data down to the half second, so this is not practical.

Also I do not want to use keyboard interrupt, have had issues with it. Are there any other solutions? All I have seen is try/except with "keyboardinterrupt"

def datacollect()
def datacypher()

while True:
    #Insert code that collects data here
    datacollect()

#end the while loop and continue on
#this is where i need help

datacypher()
print('Yay it worked, thanks for the help')

I expect to end the loop manually and then continue onto the code that acts upon the collected data.

If you need more details or have problem with my wording, let me know. I have only asked one question before. I am learning.

rum404
  • 97
  • 5
  • Use timeit.default_timer or some similar function and compare, no need to use while True. – bhathiya-perera Jun 14 '19 at 16:58
  • I'm sorry, I am confused. How can timeit.default_timer() replace my while True statement. Compare to what? – rum404 Jun 14 '19 at 17:04
  • What "issues" did you have with processing `KeyboardInterrupt`? – chepner Jun 14 '19 at 17:05
  • I want to still be able to use `KeyboardInterrupt` for terminating the entire program, but don't want to risk a user double hitting CRTL+C and terminating the entire program when they just intended to break the loop. – rum404 Jun 14 '19 at 20:04

3 Answers3

4

How about adding a key listener in a second thread? After you press Enter, you'll manually move the script to the next stage by means of a shared bool. The second thread shouldn't slow down the process since it blocks on input().

from threading import Thread
from time import sleep

done = False

def listen_for_enter_key_press():
    global done
    input()
    done = True

listener = Thread(target=listen_for_enter_key_press)
listener.start()

while not done:
    print('working..')
    sleep(1)

listener.join()

print('Yay it worked, thanks for the help')
ggorlen
  • 44,755
  • 7
  • 76
  • 106
3

One way to interrupt the loop is to use signals.

import signal

def handler(signum, stackframe):
    global DONE
    DONE = True

signal.signal(signal.SIGUSR1, handler)

DONE = False
while not DONE:
    datacollect()

datacypher()

The loop will continue until your program receives the USR1 signal (sent from the shell, for example, by kill -s USR1 <pid>, where <pid> is your program's process ID), at which point DONE will be True the next time your loop tests its value.

You can adapt this for keyboard interrupts simply by installing handler as the handler for signal.SIGINT instead of signal.SIGUSR1, since the default signal handler is what raises a KeyboardInterrupt exception in the first place.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • Thank you for the answer, I went with another solution, maybe this will be helpful to others or to myself in the future. – rum404 Jun 14 '19 at 20:01
0

One option, is you could look for the existence of a file, e.g.:

import os.path

fname = '/tmp/stop_loop'

def datacollect()
def datacypher()

while not os.path.isfile(fname):
    #Insert code that collects data here
    datacollect()

#end the while loop and continue on
#this is where i need help

datacypher()
print('Yay it worked, thanks for the help')

If that file does not exist it will continue to go through the while loop. Then, when you want to stop the while loop you can just do touch /tmp/stop_loop and the while loop will stop.

I suspect the isfile() should be a reasonably efficient, so maybe this would not be too bad.

brechmos
  • 1,278
  • 1
  • 11
  • 22
  • 1
    Thank you for the answer, I went with another solution, maybe this will be helpful to others or to myself in the future. – rum404 Jun 14 '19 at 20:01