forked from onlytiancai/codesnip
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpopentimeout.py
More file actions
64 lines (57 loc) · 1.93 KB
/
popentimeout.py
File metadata and controls
64 lines (57 loc) · 1.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#encoding=utf-8
'''
在python里调用子进程要防止子进程长时间运行,
如果处理一个web请求的时候需要调用子进程取结果,
一般可以超过一定时间后直接kill掉子进程
Popen一般会很快,不会阻塞太久,
但子进程的stdout.read方法是同步且不可以设置超时的
这样用gevent spawn一个协程开子进程read的话,
read会卡住整个协程,让所有的协程无法运行
而且用gevent.Timeout去设置超时也不管用
这就需要用到gevent.socket.wait_read了,
该方法可以等待一个文件描述符可读,
且等待可以设置超时参数,或用gevent.Timeout,
greenlet.get(timeout)来设置超时
refs:
https://bitbucket.org/denis/gevent/src/tip/examples/geventsendfile.py
'''
from subprocess import Popen, PIPE
from gevent.socket import wait_read
from sys import exc_info
try:
from errno import EBADF
except ImportError:
EBADF = 9
def runwithtimeout(cmd, timeout):
process = Popen(cmd,shell=True, stdout=PIPE, stderr=PIPE,
close_fds=True)
stdout, stderr = None, None
try:
stdout = read(process.stdout, timeout)
stderr = read(process.stderr, timeout)
except Exception, ex:
print 'popen timeout:', cmd
finally:
process.kill()
return stdout, stderr
def read(fromfile, timeout):
while True:
try:
wait_read(fromfile.fileno(), timeout)
return fromfile.read()
except:
ex = exc_info()[1]
if ex.args[0] == EBADF:
return ''
raise
if __name__ == '__main__':
from gevent import spawn
from traceback import format_exception
cmd = 'curl -I --connect-timeout %s -m %s %s ' \
% (5, 5, '202.99.160.68')
task = spawn(runwithtimeout, cmd, 10)
try:
print ''.join(task.get())
except:
type, value, tb = exc_info()
print ''.join(format_exception(type,value, tb))