2

I have a list of inputs such as fruits = [apple, banana, grape, strawberry, orange].

I have a for loop that iterates over this list and a function to work with each of the elements:

for f in fruits:
    mix(f)
    print "Finish mixing f"

My question is how to skip to the next input if the current input is taking too long. For example, mix() is working with apple, but 10 minutes have passed and it didn't get to the print line. I want it to give up on apple and pick up on banana if time is out. How can I do that?

Tom Zych
  • 13,329
  • 9
  • 36
  • 53
xukun
  • 35
  • 1
  • 6
  • _My question is how to skip to the next input if the current input is taking too long._ Well is this really a time problem? Or rather an algorithm architecture problem I mean to me, this seems like an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). What are you doing in your `mix` method ? – scharette Aug 06 '18 at 16:49
  • 3
    You tagged python-2.7, but `print("Finish mixing f")` is a Python 3 syntax. – ytu Aug 06 '18 at 16:54
  • 2
    Possible duplicate of [Python: Timeout Exception Handling with Signal.Alarm](https://stackoverflow.com/questions/28373746/python-timeout-exception-handling-with-signal-alarm) – Tom Zych Aug 06 '18 at 16:57
  • @scharette In mix method there is only one line of code which I use python package – xukun Aug 06 '18 at 17:07

1 Answers1

1

Generalizing a bit, you want to perform some operation with a time limit. If the operation finishes before the time limit is reached, all is well. If not, you want the operation to be interrupted, and execution to pass on to whatever comes next.

This suggests that we want to set up a try ... except structure, with the exception being raised after a certain amount of time has passed.

This question doesn’t specify a platform. I can’t provide code for Windows. This question and this other question seem useful for that.

Under Unix, we set up a signal handler function that raises the exception; tell Python to call that function when the SIGALRM signal is received; and set a timer that will send that signal when it times out. See example code below.

#!/usr/bin/env python2

import signal
from time import sleep    # only needed for testing

timelimit_seconds = 3    # Must be an integer

# Custom exception for the timeout
class TimeoutException(Exception):
    pass

# Handler function to be called when SIGALRM is received
def sigalrm_handler(signum, frame):
    # We get signal!
    raise TimeoutException()

# Function that takes too long for bananas and oranges
def mix(f):
    if 'n' in f:
        sleep(20)
    else:
        sleep(0.5)

fruits = ['apple', 'banana', 'grape', 'strawberry', 'orange']
for f in fruits:
    # Set up signal handler for SIGALRM, saving previous value
    old_handler = signal.signal(signal.SIGALRM, sigalrm_handler)
    # Start timer
    signal.alarm(timelimit_seconds)
    try:
        mix(f)
        print f, 'was mixed'
    except TimeoutException:
        print f, 'took too long to mix'
    finally:
        # Turn off timer
        signal.alarm(0)
        # Restore handler to previous value
        signal.signal(signal.SIGALRM, old_handler)
Tom Zych
  • 13,329
  • 9
  • 36
  • 53
  • I saw one answer that is similar but it didn't work quite right. I'll try yours. Thank you for your help. – xukun Aug 07 '18 at 15:38