Python如何給子進程設置超時時間
有一天我碰到一個需求,我需要和子進程交互,並且需要讓它在一定時間內超時。不幸的,Python2沒有讓communicate方法超時的辦法,所以communicate會一直運行到返回或者子進程自己關閉它。我在StackOverflow上找到很多中辦法來解決這個問題,但是我想我最喜歡的辦法是使用Python的Threading模塊的Timer類:
import subprocess
from threading import Timerkill = lambda process: process.kill()cmd = ["ping", "http://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()
這個例子和我的實際需求並不完全一致,但是已經很像了。首先,這裡我們有一個會一直運行下去的進程,並且我們需要和這個進程交互。在Linux上,如果你調用ping,那麼它就會一直運行下去。這就是一個很好的例子。這裡我寫了一個lambda函數killing,這個函數會調用進程的kill方法。當我啟動ping命令,並把它放在計時器里,這個計時器五秒超時,然後啟動定時器。當這個進程運行時,我們搜集進程的標準輸出和錯誤輸出,直到進程死掉。最後,我們停止計時器清場。
Python3.5增加了一個能夠接受一個timeout參數的run函數。根據文檔,這個timeout參數會被傳遞給子進程的communicate方法,並且進程超時時會拋出一個TimeoutExpired異常。讓我們來試一試:
>>> import subprocess
>>> cmd = ["ping", "http://www.google.com"]
>>> subprocess.run(cmd, timeout=5)PING http://www.google.com (216.58.216.196) 56(84) bytes of data.64 bytes from http://ord31s21-in-f4.1e100.net (216.58.216.196): icmp_seq=1 ttl=55 time=16.3 ms64 bytes from http://ord31s21-in-f4.1e100.net (216.58.216.196): icmp_seq=2 ttl=55 time=19.4 ms64 bytes from http://ord31s21-in-f4.1e100.net (216.58.216.196): icmp_seq=3 ttl=55 time=20.0 ms64 bytes from http://ord31s21-in-f4.1e100.net (216.58.216.196): icmp_seq=4 ttl=55 time=19.4 ms64 bytes from http://ord31s21-in-f4.1e100.net (216.58.216.196): icmp_seq=5 ttl=55 time=17.0 msTraceback (most recent call last):Python Shell, prompt 3, line 1File "/usr/local/lib/python3.5/subprocess.py", line 711, in run
stderr=stderr)subprocess.TimeoutExpired: Command "["ping", "http://www.google.com"]" timed out after 5 seconds
顯然確實就像文檔中所說。這真的很有用,通常我們需要捕獲這個異常
>>> try:
... subprocess.run(cmd, timeout=5)... except subprocess.TimeoutExpired:... print("process ran too long")...PING http://www.google.com (216.58.216.196) 56(84) bytes of data.64 bytes from http://ord31s21-in-f196.1e100.net (216.58.216.196): icmp_seq=1 ttl=55 time=18.3 ms64 bytes from http://ord31s21-in-f196.1e100.net (216.58.216.196): icmp_seq=2 ttl=55 time=21.1 ms
64 bytes from http://ord31s21-in-f196.1e100.net (216.58.216.196): icmp_seq=3 ttl=55 time=22.7 ms64 bytes from http://ord31s21-in-f196.1e100.net (216.58.216.196): icmp_seq=4 ttl=55 time=20.3 ms64 bytes from http://ord31s21-in-f196.1e100.net (216.58.216.196): icmp_seq=5 ttl=55 time=16.8 msprocess ran too long
現在我們捕獲到了這個異常,我們可以做些其他的事情,比如保存異常信息。有趣的是,事實上,在Python3.3 subprocess就有了timeout參數。你可以在subprocess.call, check_output, 和 check_call中使用timeout參數,在Popen.wait()中也有timeout參數。
最後還是要推薦下小編的Python學習群 491308659邀請碼(耀文)
不管你是小白還是大牛,小編我都歡迎,不定期分享乾貨,包括小編自己整理的一份2018最新的Python和0基礎入門教程,歡迎初學和進階中的小夥伴。
推薦閱讀: