Timeout is very useful when you want to limit the max time for calling a function or running a command. Here are my two Python implementations. (I?m using Python 3.6.5).
Use multiprocessing to timeout a Python function
Use one process to keep time/check timeout and another process to call this Python function.
import timefrom itertools import countfrom multiprocessing import Processdef inc_forever(): print(‘Starting function inc_forever()…’) while True: time.sleep(1) print(next(counter))def return_zero(): print(‘Starting function return_zero()…’) return 0if __name__ == ‘__main__’: # counter is an infinite iterator counter = count(0) p1 = Process(target=inc_forever, name=’Process_inc_forever’) p2 = Process(target=return_zero, name=’Process_return_zero’) p1.start() p2.start() p1.join(timeout=5) p2.join(timeout=5) p1.terminate() p2.terminate()if p1.exitcode is None: print(f’Oops, {p1} timeouts!’)if p2.exitcode == 0: print(f'{p2} is luck and finishes in 5 seconds!’)
The output is as follows. The exit code tells whether the function is a timeout (exitcode=None) or finished.
Starting function inc_forever()…Starting function return_zero()…01234Oops, <Process(Process_inc_forever, started)> timeouts!<Process(Process_return_zero, stopped)> is luck and finishes in 5 seconds!
Use subprocess to timeout an external command
Since Python 3.5, there?s a handy and recommendedrun() API in subprocess module, which has built-in timeout support.
import subprocessr = subprocess.run([‘echo’, ‘hello timeout’], timeout=5)print( f”’type(r)={type(r)}, r.args={r.args}, r.returncode={r.returncode}, r.stdout={r.stdout}, r.stderr={r.stderr}”’)try: r = subprocess.run([‘ping’, ‘www.google.com’], timeout=5)except subprocess.TimeoutExpired as e: print(e)
When timeout, it raises a TimeoutExpired exception.
hello timeouttype(r)=<class ‘subprocess.CompletedProcess’>, r.args=[‘echo’, ‘hello timeout’], r.returncode=0, r.stdout=None, r.stderr=NonePING www.google.com (216.58.194.164) 56(84) bytes of data.64 bytes from …: icmp_seq=1 ttl=54 time=10.4 ms64 bytes from …: icmp_seq=2 ttl=54 time=5.90 ms64 bytes from …: icmp_seq=3 ttl=54 time=6.19 ms64 bytes from …: icmp_seq=4 ttl=54 time=9.04 ms64 bytes from …: icmp_seq=5 ttl=54 time=16.7 msCommand ‘[‘ping’, ‘www.google.com’]’ timed out after 5 seconds
For UNIX, there?s another way to use the signal module to signal a handler to raise an exception after 5 seconds, but I think it?s a little low-level and not straightforward.