0

Most solutions for timeout context uses signals. But signals get overwritten and only the last signal handler remains. The consequence is that you cannot use a timeout context if the code is already in a timeout context (that could have been started by you, another developer, a library, a framework, who knows?).

So, basically my over-simplified use-case is this:

with Timeout(1): #A
   with Timeout(100): #B
      sleep(10) #C
   print('Fail')

This code should never print "Fail". But every implementation of Timeout() I've seen so far does the same thing:

  • Timeout A starts a timeout context
  • Timeout B starts a new timeout context (overwriting the Timeout context from A)
  • The timeout never occurs, since the computing in C takes less than 100s
  • The execution resumes without timeout context and last more than 1s

The previous example seems a little bit stupid, but the real use case is more like:

with Timeout(30):
   for a in list:
      with Timeout(10):
         heavy_computing(a)

I don't know the length of "list", I don't want to take more than 10s per element of the list and no more than 30s in total.

So my question is: What would be the best implementation of the Timeout() context that doesn't use signal and have support for embeded contexts inside contexts?

Edit:

  • The solution doesn't have to be thread-safe, just safe from another Timeout context from an higher level of scope.
  • If possible, I'd prefer a solution that is the less invasive possible, as I may use it to call a library that I didn't wrote.

Edit2:

Ok, a little clarification concerning how I consider the Timeout. For me Timeout is a non-intrusive solution to return a partial result (or no result at all) if a black-box operation takes too long. The result must be returned fastly but can be incomplete.

def function(argument):
   results = []
   with Timeout(50):
      for a in arguments:
         with Timeout(20):
            results.append(black_box(a))
   return results

If the function takes more than 50s, then the execution is aborted and an incomplet result is returned. And if black_box takes more than 10s, it will be skipped to go on with the next result.

Example: arguments = [a, b, c, d] black_box(a) takes 25s and returns w black_box(b) takes 20s and returns x black_box(c) takes 5s and returns y black_box(d) takes 10s and returns z results = [x, y]

explanations: a took more than 20s and was skipped b took 20s more seconds (40s in total) and was computed successfully c took 5s more seconds (45s in total), still less than 50s d was aborted because of the 50s timeout

The function blackbox is not aware that it is called from a Timeout context and does not contains timeout specific code.

This code is an exemple and may be a little different. Maybe we need some try.. except to catch timeout errors, etc. But black_box can't be modified.

Matthieu
  • 125
  • 6
  • [You can try a decorative approach](https://stackoverflow.com/questions/53232206/python-decorator-to-time-recursive-functions/53232620#53232620). Based on @user2357112's comment it should be thread safe. – r.ook Nov 15 '18 at 14:39
  • Possible duplicate of [Python timeout context manager with threads](https://stackoverflow.com/questions/15018519/python-timeout-context-manager-with-threads) – r.ook Nov 15 '18 at 20:16
  • @Idlehands This thread shows the solution for a timer that prints execution time, not a timeout context that stops code execution if it takes too long. – Matthieu Nov 16 '18 at 10:18
  • @Idlehands Mr Fooz' response could work but is very intrusive. And this link is aboat thread-safe timeouts, my application is mono-threaded, but have a different problem: I'd like to set multiple granularity of timeouts that don't overwrite each other. – Matthieu Nov 16 '18 at 10:35
  • Yes my confusion of the first thread came upon me thus why I linked the second one after. What is the definition of your `Timeout` right now? – r.ook Nov 16 '18 at 14:00
  • @Idlehands I edited the question to add more explanation and another example. Its a very specific need, but I hope I am clear enough... – Matthieu Nov 19 '18 at 23:18

0 Answers0