ck1987pd
ck1987pd

Reputation: 269

Aborting a loop after some time passes

I have a code which may run into long loops. These are not infinite loops but certain inputs may cause the loop to continue for extended periods. I wish to use an interrupt in case a loop goes too long. With this interrupt, the loop will re-evaluate its inputs, so a keyboard interrupt is not what I am looking for. I am using python 2.7 on Windows.

One possible approach would be polling using time.time(), yet it would be extremely inefficient. The loop itself is not long, however even in normal runs it is iterated 100k times, so I can't poll the time after each iteration, it would decrease efficiency a lot. Alternatively, I could introduce on more variable,

i=0
while i<some_very_large_number:
    function(foo, foo1, foo2)
    i=i+1

but this again, would be a mediocre solution.

In short, what I am looking for is some python equivalent to the hardware interrupt of microprocessors. I have no experience in multi-threading, so if the answer lies in multi-threading, please elaborate a little bit.

I have checked here and here, yet I do not think they answer my question. The second link could actually help yet apparently signal package is not available in Windows.

The code is long but straightforward. It basically has such a structure.

def function(foo, foo1, foo2, N):
    for i in range(N):
        performance = performance_evaluator(foo, foo1, foo2)
        if performance_takes_too_long:
             interrupt ##this if clause is the main objective of this question##
        record performance
        new_foo, new_foo1, new_foo2 = evolve(foo, foo1, foo2)

Upvotes: 1

Views: 219

Answers (2)

constt
constt

Reputation: 2320

You can also execute a long-running code in a separate worker process and try to terminate it when a timeout is exceeded and the worker has not been finished yet:

import time
from multiprocessing import Process


def process_data():

    while True:
        print("processing...")
        time.sleep(1)


def main():
    worker = Process(target=process_data)
    worker.start()

    timeout = 5
    time.sleep(timeout)

    if worker.is_alive():
        print("exceeded timeout", timeout, "sec")
        print("terminate worker", worker)
        worker.terminate()

    worker.join()
    print("is worker", worker, "alive:", worker.is_alive())


if __name__ == "__main__":
    main()

Here is the output:

processing...
processing...
processing...
processing...
processing...
exceeded timeout 5 sec
terminate worker <Process(Process-1, started)>
is worker <Process(Process-1, stopped[SIGTERM])> alive: False

Upvotes: 1

abdusco
abdusco

Reputation: 11091

One possible approach is to modify your script so that it takes its inputs via commandline arguments, then use subprocess module to run it with a timeout:

# manager.py
import subprocess

try:
    code = subprocess.call('python work.py 5', timeout=2)
    print('Ended with code:', code)
except subprocess.TimeoutExpired:
    print('Ended with timeout')


# work.py
import sys
from time import sleep

try:
    wait = int(sys.argv[1])
except:
    wait = 10

sleep(wait)
print(f'Waited for {wait} seconds')

output:

Ended with timeout

Upvotes: 1

Related Questions