0

This may be a strange request. I have an infinite While loop and each loop lasts ~7 minutes, then the program sleeps for a couple minutes to let the computer cool down, and then starts over.

This is how it looks:

import time as t

t_cooling = 120
while True:
    try:
        #7 minutes of uninterrupted calculations here
        t.sleep(t_cooling)
    except KeyboardInterrupt:
        break

Right now if I want to interrupt the process, I have to wait until the program sleeps for 2 minutes, otherwise all the calculations done in the running cycle are wasted. Moreover the calculations involve writing on files and working with multiprocessing, so interrupting during the calculation phase is not only a waste, but can potentially damage the output on the files.

I'd like to know if there is a way to signal to the program that the current cycle is the last one it has to execute, so that there is no risk of interrupting at the wrong moment. To add one more limitation, it has to be a solution that works via command line. It's not possible to add a window with a stop button on the computer the program is running on. The machine has a basic Linux installation, with no graphical environment. The computer is not particularly powerful or new and I need to use the most CPU and RAM possible.

Hope everything is clear enough.

GRB
  • 425
  • 1
  • 6
  • 20

3 Answers3

2

Not so elegant, but it works

#!/usr/bin/env python
import signal
import time as t

stop = False

def signal_handler(signal, frame):
    print('You pressed Ctrl+C!')
    global stop
    stop = True

signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')

t_cooling = 1
while not stop:
    t.sleep(t_cooling)
    print('Looping')
RedEyed
  • 2,062
  • 1
  • 23
  • 26
  • This works perfectly. Just in case someone is going to be interested in the future, this doesn't work well with the `subprocess` package, because the subprocessed program receives a CTRL+C too and doesn't complete its task. My solution was to add a handler to the other program, with just `pass` as instruction. And it's not true that this solution is unelegant. Mine was worst. – GRB Jun 28 '18 at 16:54
  • @GRB, I'm glad to help you. Also, to ignore signals use: `signal.signal(signal.SIGINT, signal.SIG_IGN)` – RedEyed Jun 28 '18 at 16:57
  • 1
    @GRB, You can ignore signals in subprocess even better! https://stackoverflow.com/questions/5045771/python-how-to-prevent-subprocesses-from-receiving-ctrl-c-control-c-sigint – RedEyed Jun 28 '18 at 17:02
1

You can use a separate Thread and an Event to signal the exit request to the main thread:

import time
import threading

evt = threading.Event()

def input_thread():
    while True:
        if input("") == "quit":
            evt.set()
            print("Exit requested")
            break

threading.Thread(target=input_thread).start()

t_cooling = 5
while True:
    #7 minutes of uninterrupted calculations here
    print("starting calculation")
    time.sleep(5)

    if evt.is_set():
        print("exiting")
        break

    print("cooldown...")
    time.sleep(t_cooling)
Felix
  • 6,131
  • 4
  • 24
  • 44
  • Sorry but this doesn't look feasible. The program generates some output, so this solution is not really practical in my case, but I suppose it can be in other cases. – GRB Jun 28 '18 at 16:51
0

Just for completeness, I post here my solution. It's very raw, but it works.

import time as t

t_cooling = 120
while True:
    #7 minutes of uninterrupted calculations here
    f = open('stop', 'r')
    stop = f.readline().strip()
    f.close()
    if stop == '0':
        t.sleep(t_cooling)
    else:
        break

I just have to create a file named stop and write a 0 in it. When that 0 is changed to something else, the program stops at the end of the cycle.

GRB
  • 425
  • 1
  • 6
  • 20