How to make subprocess timeout in Python2

       Summarize:

        python3 subprocess  wait communicate 都有timeout 

       python2 does not, and some attributes are different

      One day I came across a requirement where I needed to interact with a child process and needed to have it time out within a certain amount of time. Unfortunately, Python 2 doesn't have a way to time out the communicate method, so communicate will run until it returns or the subprocess closes it itself. I've found many ways to solve this problem on StackOverflow, but I think my favorite is to use the Timer class of Python's Threading module:

import subprocess
from threading import Timer

kill = lambda process: process.kill()
cmd = ['ping', 'www.google.com']
ping = subprocess.Popen(
    cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
my_timer = Timer(5, kill, [ping])
try:
    my_timer.start()
    stdout, stderr = ping.communicate()
finally:
    my_timer.cancel()

This example is not exactly the same as my actual needs, but it is very similar. First, here we have a process that will always run, and we need to interact with this process. On Linux, if you call ping, it just keeps running. This is a good example. Here I wrote a lambda function killing, this function will call the kill method of the process. When I start the ping command, and put it in the timer, the timer times out by five seconds and then starts the timer. When the process is running, we collect the standard output and error output of the process until the process dies. Finally, we stop the timer to clear the field.

 

Python 3.5 added a run function that accepts a timeout parameter. According to the documentation, this timeout parameter is passed to the communicate method of the child process, and a TimeoutExpired exception is thrown when the process times out. Let's try it out:

>>> import subprocess
>>> cmd = ['ping', 'www.google.com']
>>> subprocess.run(cmd, timeout=5)
PING www.google.com (216.58.216.196) 56(84) bytes of data.
64 bytes from ord31s21-in-f4.1e100.net (216.58.216.196): icmp_seq=1 ttl=55 time=16.3 ms
64 bytes from ord31s21-in-f4.1e100.net (216.58.216.196): icmp_seq=2 ttl=55 time=19.4 ms
64 bytes from ord31s21-in-f4.1e100.net (216.58.216.196): icmp_seq=3 ttl=55 time=20.0 ms
64 bytes from ord31s21-in-f4.1e100.net (216.58.216.196): icmp_seq=4 ttl=55 time=19.4 ms
64 bytes from ord31s21-in-f4.1e100.net (216.58.216.196): icmp_seq=5 ttl=55 time=17.0 ms
Traceback (most recent call last):
  Python Shell, prompt 3, line 1
  File "/usr/local/lib/python3.5/subprocess.py", line 711, in run
    stderr=stderr)
subprocess.TimeoutExpired: Command '['ping', 'www.google.com']' timed out after 5 seconds

Apparently it does exactly as it says in the documentation. This is really useful, usually we need to catch this exception

>>> try:
...     subprocess.run(cmd, timeout=5)
... except subprocess.TimeoutExpired:
...     print('process ran too long')
... 
PING www.google.com (216.58.216.196) 56(84) bytes of data.
64 bytes from ord31s21-in-f196.1e100.net (216.58.216.196): icmp_seq=1 ttl=55 time=18.3 ms
64 bytes from ord31s21-in-f196.1e100.net (216.58.216.196): icmp_seq=2 ttl=55 time=21.1 ms
64 bytes from ord31s21-in-f196.1e100.net (216.58.216.196): icmp_seq=3 ttl=55 time=22.7 ms
64 bytes from ord31s21-in-f196.1e100.net (216.58.216.196): icmp_seq=4 ttl=55 time=20.3 ms
64 bytes from ord31s21-in-f196.1e100.net (216.58.216.196): icmp_seq=5 ttl=55 time=16.8 ms
process ran too long

现在我们捕获到了这个异常,我们可以做些其他的事情,比如保存异常信息。有趣的是,事实上,在Python3.3 subprocess就有了timeout参数。你可以在subprocess.call, check_output, 和 check_call中使用timeout参数,在Popen.wait()中也有timeout参数。

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326995308&siteId=291194637