python的requests.session()_[Python] 用Session()优化requests的性能

前言

只要用python做过一些web开发,多少都用过requests这个模块,简单,方便的HTTP客户端,大家都爱。不过,如果你只是停留在requests.get()或者requests.post()这样的调用层面上,那你的程序跑起来,可能有点慢,这篇文章将会回答你,慢的其中一个原因,以及优化的方法。

普通的调用有什么问题?

继续之前,我们先来回顾两件事——HTTP/1.1基于TCP,HTTPS基于TLS。

完成一次HTTP的接口调用或者普通的请求抓取数据,一定也包含了TCP的包交互,如果是HTTPS,还会包含TLS的部分。

为什么提这两件事呢,我用一个实际的HTTP的接口调用的例子来说明——

如下所示,是一段简单的HTTP调用的代码,IP地址和token出于敏感原因隐藏了。

import requests

import json

url1 = "https://XX.XX.XX.XX/api/v2/cmdb/firewall/address"

url2 = "https://XX.XX.XX.XX/api/v2/cmdb/firewall/policy/1"

token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX"

header = {

"Content-type": "application/json",

"Accept": "application/json",

"Authorization": token

}

res1 = requests.get(url=url1, headers=header, verify=False)

res2 = requests.get(url=url1, headers=header, verify=False)

print(res1)

print(res2)

这段代码在执行的同时,我开了Wireshark抓包,会抓到两个TCP流,我们取第一个来看(末尾处混入了第二个流的第一个SYN,因为我没有去过滤)。

仔细观察,Application Data出现在自第一个包之后的31ms,而整个TCP数据流到最后一个ACK收到,也就经过了41ms,换言之,TCP以及TLS的包交互,消耗了30ms,约70%。

第二个流的情况和第一个基本类似,TCP以及TLS的交互消耗了很多时间。

如果你的程序涉及频繁的接口调用,譬如笔者调用防火墙的接口,常常一个策略里要调用多个不同的接口配置不同的对象,每次调用都要走一遍完整的TCP流程,在频繁调用,压力大的时候(比如有同事会一股脑提交N多的策略),可能会有这么几个问题——冗余的TCP开销导致程序执行慢,效率低。

网络设备内部也是个Linux,短时间大量的TCP连接不仅造成CPU层面的压力,还可能引发著名的TIME-WAIT问题。

所以,怎么办?——TCP长连接,或者说保持TCP连接。

而requests模块给出了实现的办法——requests.Session()。

requests.Session(),复用TCP

参考官方的说明。Keep-Alive

Excellent news — thanks to urllib3, keep-alive is 100% automatic within a session!Any requests that you make within a session will automatically reuse the appropriate connection!

Note that connections are only released back to the pool for reuse once all body data has been read; be sure to either set stream to False or read the content property of the Response object.

关键部分已经用粗斜体标出。再来看一下Session()的用法。

下面这个是官方的示例,大概就是,实例化一个Session()对象,然后就像正常的调用那么用就好了 。

s = requests.Session()

s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')

r = s.get('https://httpbin.org/cookies')

print(r.text)

改改我们自己的代码看看效果

现在,代码改成下面这样。

import requests

import json

s = requests.Session()

url1 = "https://XX.XX.XX.XX/api/v2/cmdb/firewall/address"

url2 = "https://XX.XX.XX.XX/api/v2/cmdb/firewall/policy/1"

token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX"

header = {

"Content-type": "application/json",

"Accept": "application/json",

"Authorization": token

}

res1 = s.get(url=url1, headers=header, verify=False)

res2 = s.get(url=url1, headers=header, verify=False)

print(res1)

print(res2)

运行,然后抓包,结果——

现在,TCP和TLS只会建立和拆除一次,两个get请求总的执行时间是57ms,而之前是81ms,并且,复用同一个TCP的HTTP越多,效果越好。

传入requests.Session() 对象

众所周知,Python是一个套娃语言,套娃乃是Python的传统艺能。

我们写Python代码的时候,难免要把各种接口抽象成一个个函数,类,然后调来调去,这就麻烦了,我在哪去实例化Session()类呢?——在最外层的入口函数的地方。

我们把上面的代码做个简单的修改。

import requests

import json

s = requests.Session()

url1 = "https://XX.XX.XX.XX/api/v2/cmdb/firewall/address"

url2 = "https://XX.XX.XX.XX/api/v2/cmdb/firewall/policy/1"

url3 = "https://XX.XX.XX.XX/api/v2/cmdb/webfilter/profile"

url4 = "https://XX.XX.XX.XX/api/v2/cmdb/webfilter/urlfilter"

token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX"

header = {

"Content-type": "application/json",

"Accept": "application/json",

"Authorization": token

}

def session_test(func, url, header):

res = func.get(url=url1, headers=header, verify=False)

return res

print(session_test(func=s, url=url1, header=header))

print(session_test(func=s, url=url2, header=header))

print(session_test(func=s, url=url3, header=header))

print(session_test(func=s, url=url4, header=header))

请注意,s是在全局下实例化的,所以只有整个代码执行结束,s才会消失。

当然,你也可以把s在一个函数中实例化,都一样。

这里真正执行get请求的函数是session_test,它接受一个func参数,也就是我们要把s传进去,换言之func = s。

session_test每次执行结束后,只是func会被垃圾回收,s仍然存在。

所以,这个代码在执行后,TCP仍然是复用的。

如上所示,4个请求,78ms,对比之前两个请求就消耗了81ms……如果不做这层优化,四个请求将会消耗160+ms,网络差的时候,这个问题会更加严重。

所以,你get到了吗?

晚安。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值