gpt4 book ai didi

python - 如果 socket.setdefaulttimeout() 不起作用怎么办?

转载 作者:太空狗 更新时间:2023-10-29 20:36:09 25 4
gpt4 key购买 nike

我正在编写一个脚本(多线程)来从网站检索内容,并且该网站不是很稳定,所以时不时会有挂起的 http 请求,甚至无法通过 socket.setdefaulttimeout 超时()。由于我无法控制该网站,我唯一能做的就是改进我的代码,但我现在已经没有想法了。

示例代码:

socket.setdefaulttimeout(150)

MechBrowser = mechanize.Browser()
Header = {'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 GTB7.1 (.NET CLR 3.5.30729)'}
Url = "http://example.com"
Data = "Justatest=whatever&letstry=doit"
Request = urllib2.Request(Url, Data, Header)
Response = MechBrowser.open(Request)
Response.close()

如何强制退出挂起的请求?其实我想知道为什么 socket.setdefaulttimeout(150) 首先不工作。任何人都可以帮助我吗?

已添加:(是的,问题仍未解决)

好的,我听从了 tomasz 的建议并将代码更改为 MechBrowser.open(Request, timeout = 60),但同样的事情发生了。直到现在我仍然随机收到挂起请求,有时是几个小时,有时可能是几天。现在我该怎么做?有没有办法强制这些挂起的请求退出?

最佳答案

虽然 socket.setsocketimeout 将为新套接字设置默认超时,但如果您不直接使用套接字,则可以轻松覆盖该设置。特别是,如果库在其套接字上调用 socket.setblocking,它将重置超时。

urllib2.open 有一个超时参数,但是urllib2.Request 没有超时参数。当您使用 mechanize 时,您应该引用他们的文档:

Since Python 2.6, urllib2 uses a .timeout attribute on Request objects internally. However, urllib2.Request has no timeout constructor argument, and urllib2.urlopen() ignores this parameter. mechanize.Request has a timeout constructor argument which is used to set the attribute of the same name, and mechanize.urlopen() does not ignore the timeout attribute.

来源:http://wwwsearch.sourceforge.net/mechanize/documentation.html

---编辑---

如果 socket.setsockettimeout 或将超时传递给 mechanize 可以使用较小的值,但不能使用较高的值,则问题的根源可能完全不同。一件事是你的图书馆可能会打开多个连接(这里归功于@Cédric Julien),所以超时适用于 socket.open 的每一次尝试,如果它没有因第一次失败而停止 - 可能需要 timeout * num_of_conn 秒。另一件事是 socket.recv:如果连接真的很慢而且你够倒霉,整个请求可能会占用 timeout * incoming_bytes 就像每个 socket.recv 我们可以获得一个字节,并且每次这样的调用都可能需要 timeout 秒。由于您不太可能遭受这种黑暗场景的影响(每个超时秒一个字节?您必须是一个非常粗鲁的男孩),很可能会要求花费很长时间才能实现非常慢的连接和非常高的超时。

唯一的解决办法是强制整个请求超时,但这里与套接字无关。如果您使用的是 Unix,则可以使用带有 ALARM 信号的简单解决方案。您将信号设置为在 timeout 秒后发出,您的请求将被终止(不要忘记捕获它)。您可能喜欢使用 with 语句来使其简洁易用,例如:

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"

如果想要比这更便携,你必须使用一些更大的枪,例如 multiprocessing,所以你会产生一个进程来调用你的请求并在逾期时终止它。由于这将是一个单独的进程,您必须使用某些东西将结果传回您的应用程序,它可能是 multiprocessing.Pipe。例子来了:

from multiprocessing import Process, Pipe
import time

def request(sleep, result):
"""Your http request example"""
time.sleep(sleep)
return result

class TimeoutWrapper():
"""Timeout wrapper using separate process"""
def __init__(self, func, timeout):
self.func = func
self.timeout = timeout

def __call__(self, *args, **kargs):
"""Run func with timeout"""
def pmain(pipe, func, args, kargs):
"""Function to be called in separate process"""
result = func(*args, **kargs) # call func with passed arguments
pipe.send(result) # send result to pipe

parent_pipe, child_pipe = Pipe() # Pipe for retrieving result of func
p = Process(target=pmain, args=(child_pipe, self.func, args, kargs))
p.start()
p.join(self.timeout) # wait for prcoess to end

if p.is_alive():
p.terminate() # Timeout, kill
return None # or raise exception if None is acceptable result
else:
return parent_pipe.recv() # OK, get result

print TimeoutWrapper(request, 3)(1, "OK") # prints OK
print TimeoutWrapper(request, 1)(2, "Timeout") # prints None

如果你想强制请求在固定的秒数后终止,你真的没有太多选择。 socket.timeout 将为单个套接字操作(连接/接收/发送)提供超时,但如果您有多个套接字操作,则执行时间可能会很长。

关于python - 如果 socket.setdefaulttimeout() 不起作用怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8464391/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com