2012-03-16 191 views
2

我因爲聽了這個問題張貼在這裏:設置超時mechanize.Browser

What should I do if socket.setdefaulttimeout() is not working?

,試圖拿出一個解決方案,殺死請求時,我mechanize.Browser對象花費的時間太長了,我有在嘗試用在托馬斯的編輯第一個解決方案(轉貼在這裏爲清楚起見):

import signal, time 

def request(arg): 
    """Your http request""" 
    time.sleep(2) 
    return arg 

class Timeout(): 
    """Timeout class using ALARM signal""" 
    class Timeout(Exception): pass 

    def __init__(self, sec): 
    self.sec = sec 

    def __enter__(self): 
    signal.signal(signal.SIGALRM, self.raise_timeout) 
    signal.alarm(self.sec) 

    def __exit__(self, *args): 
    signal.alarm(0) # disable alarm 

    def raise_timeout(self, *args): 
    raise Timeout.Timeout() 

# Run block of code with timeouts 
try: 
    with Timeout(3): 
    print request("Request 1") 
    with Timeout(1): 
    print request("Request 2") 
except Timeout.Timeout: 
    print "Timeout" 

# Prints "Request 1" and "Timeout" 

當我從我的使用終端運行這個python timeout.py(版本是Python 2.7.2+,我在Ubuntu 11.10上eiric山貓),沒有例外thrown-相反,它只是簡單地打印

Request 1 
Request 2 

可能有人請解釋如何解決這一問題?對這些signal.alarmsignal.signal調用進行的解釋也很棒。

非常感謝您的寶貴時間!

編輯:

運行strace -f python timeout.py產量:

alarm(3)        = 0 
select(0, NULL, NULL, NULL, {2, 0})  = 0 (Timeout) 
fstat64(1, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0 
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb740c000 
alarm(0)        = 1 
rt_sigaction(SIGALRM, {0x812f450, [], 0}, {0x812f450, [], 0}, 8) = 0 
alarm(1)        = 0 
select(0, NULL, NULL, NULL, {2, 0})  = 0 (Timeout) 
alarm(0)        = 0 
rt_sigaction(SIGINT, {SIG_DFL, [], 0}, {0x812f450, [], 0}, 8) = 0 
rt_sigaction(SIGALRM, {SIG_DFL, [], 0}, {0x812f450, [], 0}, 8) = 0 
write(1, "Request 1\nRequest 2\n", 20) = 20 
exit_group(0)       = ? 
+1

也許'sleep'使用'SIGALRM'內部,這是合理的,並會弄亂你的測試。嘗試做一個阻塞I/O操作而不是睡眠(從標準輸入讀取,不要在控制檯輸入任何東西)。 – Useless 2012-03-16 16:11:45

+1

它適用於我,同一版本的Ubuntu。你沒有忘記'#!/ usr/bin/env python'或'chmod 777 '是不是? – John 2012-03-16 16:14:38

+0

代碼工作在我的環境預期(CPython的2.6.5/Ubuntu的9.04) – 2012-03-16 16:16:33

回答

1

如果你想知道這裏發生了什麼,請嘗試:

$ strace -f python timeout.py 

對我來說,(與Python 2.6運行Debian 6)這工作。 strace輸出的重要部分:

alarm(3)        = 0 
select(0, NULL, NULL, NULL, {2, 0})  = 0 (Timeout) 
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 15), ...}) = 0 
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = x7f0fbbe06000 
write(1, "Request 1\n", 10Request 1)    = 10 
alarm(0)        = 1 
rt_sigaction(SIGALRM, {0x4d0a90, [], SA_RESTORER, 0x7f0fbb9deff0}, {0x4d0a90, [], SA_RESTORER, 0x7f0fbb9deff0}, 8) = 0 
alarm(1)        = 0 
select(0, NULL, NULL, NULL, {2, 0})  = ? ERESTARTNOHAND (To be restarted) 
--- SIGALRM (Alarm clock) @ 0 (0) --- 
rt_sigreturn(0xffffffff)    = -1 EINTR (Interrupted system call) 
alarm(0)        = 0 
write(1, "Timeout\n", 8Timeout 
)    = 8 

報警(3)被調用;請求1通過;警報(1)被稱爲超時。

+0

我已經在編輯中發佈了我的'strace'的輸出。我真的很困惑,爲什麼這對我不起作用,但是對於其他人來說 - 似乎在我的'strace'中'write'命令只被調用一次,並且異常不會被拋出。有任何想法嗎?謝謝。 – ZenLikeThat 2012-03-16 17:32:30