Skip to main content
 首页 » 编程设计

python之为 mechanize.Browser 设置超时

2025年05月04日12tuyile006

我正在细读这里发布的问题:

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

当我的 mechanize.Browser 对象花费太长时间时,尝试想出一个终止请求的解决方案,我一直在试验 tomasz 编辑中的第一个解决方案(为清楚起见,在此处重新发布) :

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 Oneiric Ocelot)从我的终端运行它时,没有抛出异常 - 而不是简单地打印

Request 1 
Request 2 

有人可以解释一下如何解决这个问题吗?对那些 signal.alarm 和 signal.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)                           = ? 

请您参考如下方法:

如果你想知道这里发生了什么,请尝试:

$ 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 通过; alarm(1) 被调用,给出超时。