Python 为什么套接字实现比请求慢?
我有一个Python3.4脚本,可以获取多个网页。首先,我使用请求库获取页面:Python 为什么套接字实现比请求慢?,python,sockets,python-requests,Python,Sockets,Python Requests,我有一个Python3.4脚本,可以获取多个网页。首先,我使用请求库获取页面: def get_page_requsets(url): r = requests.get(url) return r.content 上述代码给出了每秒4.6个请求的平均速度。 要提高速度,我重写了函数以使用套接字库: def get_page_socket(url): url = urlparse(url) sock = socket.socket(socket.AF_INET,
def get_page_requsets(url):
r = requests.get(url)
return r.content
上述代码给出了每秒4.6个请求的平均速度。
要提高速度,我重写了函数以使用套接字库:
def get_page_socket(url):
url = urlparse(url)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((url.netloc, 80))
req = '''
GET {} HTTP/1.1\r
Host: {}\r
Connection: Keep-Alive\r
\r
'''.format(url.path, url.host, uagent)
sock.send(req.encode())
reply = b''
while True:
chunk = sock.recv(65535)
if chunk:
reply += chunk
else:
break
sock.close()
return reply
平均速度下降到每秒4.04个请求。我不希望赛车的速度提高,但希望稍微提高,因为球座的水平较低。
这是库问题还是我做错了什么?
请求使用,它可以非常有效地处理HTTP连接。尽可能重复使用与同一服务器的连接,从而节省套接字连接和拆卸成本:
- 使用可选的客户端证书验证,对多个请求重新使用相同的套接字连接。请参阅:
HTTPConnectionPool
和HTTPSConnectionPool
此外,urllib3
和请求
向服务器公布它们可以处理压缩响应;通过压缩,您可以在相同的时间内传输更多的数据,从而每秒产生更多的请求
- 支持gzip和deflate解码。请参阅:
decode\u gzip()
和decode\u deflate()
urllib3
也使用套接字(尽管是通过);重新发明这个轮子没有什么意义。也许您应该考虑使用线程、多处理或Eventlet并行获取URL;请求
作者有一个可以提供帮助的方法。另一种实现并发性的方法是结合使用,因为HTTP请求主要等待网络I/O。缓慢可能仅仅是因为您的HTTP错误:您发出HTTP/1.1请求,甚至明确指定连接保持活动状态(甚至不需要,因为这是HTTP/1.1隐含的)。但是,您只是从套接字读取数据,并期望服务器在请求完成后关闭连接。但服务器不会这样做,它会等待更多来自您的请求,因为“保持活动”,只有在一段时间不活动后才关闭连接,这取决于服务器配置。幸运的是,您可以在很短的超时时间内连接到一个服务器,在这个服务器上,您仍然每秒收到4.04个请求,而在其他服务器上,您的代码每分钟只收到很少的请求
如果要使用普通套接字发出简单的HTTP请求,请使用HTTP/1.0,不要使用keep-alive。然后,您可以一直读到服务器关闭,并且您也不必处理HTTP/1.1引入的分块传输编码。您也不必处理压缩编码,因为您并没有特别接受它们(但一些坏掉的服务器还是会发送它们)
但是,虽然这将使您的代码比现在更快,但它不会像请求那样快,因为所有这些都是为了提高速度而添加的保持活动、压缩等。要正确地重新实现这一切并不是那么容易,因此我建议您继续使用请求库。也许请求库的实现与您的实现大致相同,在这种情况下,它们的性能类似也就不足为奇了。每秒4或5个请求时,您不受客户端资源的限制,您显然受到网络或服务器的限制。因此,如果直接使用套接字,则差别不大。事实上,高级库应该更聪明,从而更快。如果是网络延迟,请使用;如果是吞吐量,则使用压缩;如果服务器被限制,请使用并行连接。一个快速的解决方案是使用curl\u multi
接口,或者请求离实现还很远。:-)