How to Timeout Function in Python, Timeout Less Than a Second

How to timeout function in python, timeout less than a second

Solution:

I've just modified a script posted here: Timeout function if it takes too long to finish.

And here is the code:

from functools import wraps
import errno
import os
import signal

class TimeoutError(Exception):
pass

def timeout(seconds=10, error_message=os.strerror(errno.ETIME)):
def decorator(func):
def _handle_timeout(signum, frame):
raise TimeoutError(error_message)

def wrapper(*args, **kwargs):
signal.signal(signal.SIGALRM, _handle_timeout)
signal.setitimer(signal.ITIMER_REAL,seconds) #used timer instead of alarm
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0)
return result
return wraps(func)(wrapper)
return decorator

And then you can use it like this:

from timeout import timeout 
from time import time

@timeout(0.01)
def loop():
while True:
pass
try:
begin = time.time()
loop()
except TimeoutError, e:
print "Time elapsed: {:.3f}s".format(time.time() - begin)

Which prints

Time elapsed: 0.010s

Timeout on a function call

You may use the signal package if you are running on UNIX:

In [1]: import signal

# Register an handler for the timeout
In [2]: def handler(signum, frame):
...: print("Forever is over!")
...: raise Exception("end of time")
...:

# This function *may* run for an indetermined time...
In [3]: def loop_forever():
...: import time
...: while 1:
...: print("sec")
...: time.sleep(1)
...:
...:

# Register the signal function handler
In [4]: signal.signal(signal.SIGALRM, handler)
Out[4]: 0

# Define a timeout for your function
In [5]: signal.alarm(10)
Out[5]: 0

In [6]: try:
...: loop_forever()
...: except Exception, exc:
...: print(exc)
....:
sec
sec
sec
sec
sec
sec
sec
sec
Forever is over!
end of time

# Cancel the timer if the function returned before timeout
# (ok, mine won't but yours maybe will :)
In [7]: signal.alarm(0)
Out[7]: 0

10 seconds after the call signal.alarm(10), the handler is called. This raises an exception that you can intercept from the regular Python code.

This module doesn't play well with threads (but then, who does?)

Note that since we raise an exception when timeout happens, it may end up caught and ignored inside the function, for example of one such function:

def loop_forever():
while 1:
print('sec')
try:
time.sleep(10)
except:
continue

Timeout function if it takes too long to finish

The process for timing out an operations is described in the documentation for signal.

The basic idea is to use signal handlers to set an alarm for some time interval and raise an exception once that timer expires.

Note that this will only work on UNIX.

Here's an implementation that creates a decorator (save the following code as timeout.py).

import errno
import os
import signal
import functools

class TimeoutError(Exception):
pass

def timeout(seconds=10, error_message=os.strerror(errno.ETIME)):
def decorator(func):
def _handle_timeout(signum, frame):
raise TimeoutError(error_message)

@functools.wraps(func)
def wrapper(*args, **kwargs):
signal.signal(signal.SIGALRM, _handle_timeout)
signal.alarm(seconds)
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0)
return result

return wrapper

return decorator

This creates a decorator called @timeout that can be applied to any long running functions.

So, in your application code, you can use the decorator like so:

from timeout import timeout

# Timeout a long running function with the default expiry of 10 seconds.
@timeout
def long_running_function1():
...

# Timeout after 5 seconds
@timeout(5)
def long_running_function2():
...

# Timeout after 30 seconds, with the error "Connection timed out"
@timeout(30, os.strerror(errno.ETIMEDOUT))
def long_running_function3():
...

How can I implement a timeout function?

Use signal.alarm, following the example given in the documentation of the signal module.

class TimesUpError(RuntimeException):
pass

def handler(signum, frame):
raise TimesUpError

signal.signal(signal.SIGALRM, handler)
signal.alarm(15)
try:
while SOME_CONDITION:
time.sleep(1)
except TimesUpError:
print("Times up, continuing")
finally:
signal.alarm(0)

Depending on what SOME_CONDITION is, you may be able to use signal.sigtimedwait instead of the loop.

Simplest way to timeout a Python function on Windows

depends on use case ... for this very specific example

import time

def hello(timeout=5):
start_time = time.time()
for _ in range(10):
if time.time()-start_time > timeout:
break
print("hello")
time.sleep(1)

hello()

is one way you could do it

alternatively you could use multiprocessing

import multiprocessing
...
if __name__ == "__main__":
proc = multiprocessing.Process(target=hello)
proc.start()
time.sleep(5)
proc.terminate()

How to set timeout for a block of code which is not a function python3

i think implement this efficiently without using functions not possible , look this code ..

import datetime as dt
print("Doing different things")
# store
time_out_after = dt.timedelta(seconds=60)
start_time = dt.datetime.now()
for i in range(10):
if dt.datetime.now() > time_started + time_out:
break
else:
# Doing some heavy stuff
print("Done. Continue with the following code")

the problem : the timeout will checked in the beginning of every loop cycle, so it may be take more than the specified timeout period to break of the loop, or in worst case it maybe not interrupt the loop ever becouse it can't interrupt the code that never finish un iteration.


update :

as op replayed, that he want more efficient way, this is a proper way to do it, but using functions.

import asyncio

async def test_func():

print('doing thing here , it will take long time')
await asyncio.sleep(3600) # this will emulate heaven task with actual Sleep for one hour
return 'yay!' # this will not executed as the timeout will occur early

async def main():
# Wait for at most 1 second
try:
result = await asyncio.wait_for(test_func(), timeout=1.0) # call your function with specific timeout
# do something with the result
except asyncio.TimeoutError:
# when time out happen program will break from the test function and execute code here
print('timeout!')
print('lets continue to do other things')

asyncio.run(main())

Expected output:

doing thing here , it will take long time

timeout!

lets continue to do other things

note:

now timeout will happen after exactly the time you specify. in this example code, after one second.

you would replace this line:

await asyncio.sleep(3600)

with your actual task code.

try it and let me know what do you think. thank you.

read asyncio docs:
link

update 24/2/2019

as op noted that asyncio.run introduced in python 3.7 and asked for altrnative on python 3.6

asyncio.run alternative for python older than 3.7:

replace

asyncio.run(main())

with this code for older version (i think 3.4 to 3.6)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()


Related Topics



Leave a reply



Submit