Python requests请求极慢

编程入门 行业动态 更新时间:2024-10-22 09:30:49

<a href=https://www.elefans.com/category/jswz/34/1770869.html style=Python requests请求极慢"/>

Python requests请求极慢

问题发现

调用钉钉机器人API发送消息,调试的时发现问题,这个接口调用速度极慢。经多次测试,平均耗时2分钟。

​​同样的接口使用postman却只耗时200毫秒~

后来发现,凡是钉钉的API oapi.dingtalk,使用requests就特别慢,而postman就很正常。基本可以排除网络原因,那么是什么因素导致requests这么慢呢?

原因分析

先看下requests源码:

# requests实际调用的urllib3实现
# 而urllib3最终使用socket实现真正的网络通信
# 以下是urllib3 create_connection()部分源码
def create_connection(address,timeout=socket._GLOBAL_DEFAULT_TIMEOUT,source_address=None,socket_options=None,
):host, port = addressif host.startswith("["):host = host.strip("[]")err = None# 注意这一行family = allowed_gai_family()try:host.encode("idna")except UnicodeError:return six.raise_from(LocationParseError(u"'%s', label empty or too long" % host), None)for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):af, socktype, proto, canonname, sa = ressock = Nonetry:# 经过跟踪,代码卡在了这里sock = socket.socket(af, socktype, proto)# ...

create_connection()做的事情其实很简单,设置参数,建立socket连接。而建立scoket连接,本身网络又没有问题,不可能那么慢,那么问题出在哪里了呢?
往上看,host没什么可说的,那么很明显了,问题出在这一行:

	# Using the value from allowed_gai_family() in the context of getaddrinfo lets# us select whether to work with IPv4 DNS records, IPv6 records, or both.# The original create_connection function always returns all records.family = allowed_gai_family()

通过注释可以知道,family的作用是requests使用IPv4还是IPv6:

def allowed_gai_family():"""This function is designed to work in the context ofgetaddrinfo, where family=socket.AF_UNSPEC is the default andwill perform a DNS search for both IPv6 and IPv4 records."""family = socket.AF_INETif HAS_IPV6:family = socket.AF_UNSPECreturn family

注意if那里,若系统支持IPv6,那么HAS_IPV6=True。现代计算机基本都支持IPv6,所以HAS_IPV6差不多相当于常量了,也就是说只有系统支持,那么requests默认使用IPv6去连接服务器

socket.getaddrinfo()返回的结果也验证了我的这个猜想:

(‘2401:b180:2000:60::f’, 443, 0, 0)


从函数名大概可以猜测socket.getaddrinfo()的功能,用host、port、family等解析出服务器的IP地址,2401:b180:2000:60::f是IPv6地址,再加上前面分析的family作用,大概可以推导出这个问题的原因所在了:

如果服务器支持IPv6,那么requests默认会使用IPv6去连接服务器,而由于网络原因致使IPv6连接建立很慢,socket.socket()又是阻塞的,所以程序就会一直卡在这里,导致问题出现。

分别在家和公司(两个不同网络)下测试同一脚本,发现公司网络连接IPv6速度极慢,而家里则正常连接,证实是网络原因导致此问题。

解决办法

知道原因,解决起来就简单了,既然requests默认使用IPv6,那么强制让丫使用IPv4不就行了吗,直接重写allowed_gai_family()

import socket
import urllib3def allowed_gai_family():return socket.AF_INETurllib3.util.connection.allowed_gai_family = allowed_gai_family

再次运行:

搞定!

参考文档

一开始出现问题时,我也尝试搜过,但大部分答案都是用session,我也试过,几乎没用。后来在stackoverflow上找到一点灵感,大家有兴趣可以去看看:

更多推荐

Python requests请求极慢

本文发布于:2024-03-10 05:35:01,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1727122.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Python   requests

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!