valkey之sdscatrepr 函数优化解析

一、函数功能概述

sds sdscatrepr(sds s, const char *p, size_t len)函数的核心功能是将字符串p追加到字符串s中。在追加过程中,它会对字符串p中的字符进行判断,使用isprint()函数识别不可打印字符,并对这些字符进行转义处理,确保最终追加后的字符串s符合特定的格式要求 。
此函数主要用在Monitor模式下。

二、原始版本代码分析

sds sdscatrepr(sds s, const char *p, size_t len) {s = sdscatlen(s,"\"",1);while(len--) {switch(*p) {case '\\':case '"':s = sdscatprintf(s,"\\%c",*p);break;case '\n': s = sdscatlen(s,"\\n",2); break;case '\r': s = sdscatlen(s,"\\r",2); break;case '\t': s = sdscatlen(s,"\\t",2); break;case '\a': s = sdscatlen(s,"\\a",2); break;case '\b': s = sdscatlen(s,"\\b",2); break;default:if (isprint(*p))s = sdscatprintf(s,"%c",*p);elses = sdscatprintf(s,"\\x%02x",(unsigned char)*p);break;}p++;}return sdscatlen(s,"\"",1);
}

2.1 实现逻辑

  1. 首先在字符串s末尾追加双引号"
  2. 然后通过while循环遍历字符串p,对每个字符进行判断:
  • 若字符是\",使用sdscatprintf函数将其转义后追加到s中。
  • 若字符是换行符\n、回车符\r、制表符\t、响铃符\a、退格符\b,分别使用sdscatlen函数将对应的转义序列追加到s中。
  • 对于其他字符,先判断是否为可打印字符。如果是,使用sdscatprintf函数以格式化字符形式追加;如果不是,将其以十六进制字符串形式追加到s中。
  1. 遍历结束后,在字符串s末尾再追加一个双引号"

2.2 性能瓶颈

  1. 频繁内存申请:目标字符串s的可用空间不一定能容纳字符串p,在执行sdscatlensdscatprintf函数时,若空间不足会触发s的重新空间申请。当字符串p较长时,频繁的空间申请操作会严重影响函数性能。

  2. 可打印字符处理低效:对于可打印字符,使用sdscatprintf(s,"%c",*p);进行格式化追加,相比直接赋值操作,这种方式会调用vsnprintf函数,额外的函数调用和格式化处理消耗了大量性能。

三、预分配版本代码分析

sds sdscatrepr(sds s, const char *p, size_t len) {s = sdsMakeRoomFor(s, len + 2);s = sdscatlen(s,"\"",1);while(len--) {switch(*p) {case '\\':case '"':s = sdscatprintf(s,"\\%c",*p);break;case '\n': s = sdscatlen(s,"\\n",2); break;case '\r': s = sdscatlen(s,"\\r",2); break;case '\t': s = sdscatlen(s,"\\t",2); break;case '\a': s = sdscatlen(s,"\\a",2); break;case '\b': s = sdscatlen(s,"\\b",2); break;default:if (isprint(*p))s = sdscatlen(s, p, 1);elses = sdscatprintf(s,"\\x%02x",(unsigned char)*p);break;}p++;}return sdscatlen(s,"\"",1);
}

3.1 优化思路

  1. 空间预分配:在函数入口处,通过s = sdsMakeRoomFor(s, len + 2);提前为字符串s分配足够的空间,其中+2是为了容纳首尾的双引号。这样在大多数情况下,后续追加字符串p时,不会频繁触发s的内存重新申请,减少了内存操作的开销。

  2. 可打印字符处理优化:将处理可打印字符的s = sdscatprintf(s,"%c",*p);替换为s = sdscatlen(s, p, 1);,避免了调用vsnprintf函数,直接使用memcpy进行字符复制,提高了可打印字符追加的效率。

3.2 优化效果

测试场景吞吐量(requests per second)平均延迟(msec)最小延迟(msec)50% 分位延迟(msec)95% 分位延迟(msec)99% 分位延迟(msec)最大延迟(msec)
优化前(无监控)264669.281.6630.3041.6232.4873.38345.855
优化前(1 个监控)78633.665.9170.3124.81511.71131.775171.391
优化后(无监控)2557611.7100.3201.6312.7273.57936.415
优化后(1 个监控)106142.474.3470.3283.6957.78318.031107.711

从结果看吞吐从788633.66/s提升到了106142.47,提升幅度约34%。

3.3 仍存在的问题

  1. 尽管进行了空间预分配,但当字符串p中存在大量不可见字符时,由于对不可见字符的处理方式仍可能导致空间不足,进而触发s的内存重新申请,影响性能。

  2. sdscatlen函数分析

sds sdscatlen(sds s, const void *t, size_t len) {size_t curlen = sdslen(s);s = sdsMakeRoomFor(s, len);if (s == NULL) return NULL;memcpy(s + curlen, t, len);sdssetlen(s, curlen + len);s[curlen + len] = '\0';return s;
}

从该函数逻辑可以看出,对于可打印字符,在使用sdscatlen函数追加时,每追加一个字符就会调用一次memcpy函数。当处理长字符串p时,频繁调用memcpy会带来一定的性能损耗。

四、批处理版本代码分析

sds sdscatrepr(sds s, const char *p, size_t len) {s = sdsMakeRoomFor(s, len + 2);s = sdscatlen(s, "\"", 1);while (len) {if (isprint(*p)) {const char *start = p;while (len && isprint(*p)) {len--;p++;}s = sdscatlen(s, start, p - start);} else {switch (*p) {case '\\':case '"': s = sdscatprintf(s, "\\%c", *p); break;case '\n': s = sdscatlen(s, "\\n", 2); break;case '\r': s = sdscatlen(s, "\\r", 2); break;case '\t': s = sdscatlen(s, "\\t", 2); break;case '\a': s = sdscatlen(s, "\\a", 2); break;case '\b': s = sdscatlen(s, "\\b", 2); break;default:s = sdscatprintf(s, "\\x%02x", (unsigned char)*p);break;}p++;len--;}}return sdscatlen(s, "\"", 1);
}

4.1 优化逻辑

  1. 调整判断顺序:在遍历字符串p时,优先判断字符是否为可打印字符。如果是,以当前字符为起始点,继续判断后续字符是否也为可打印字符,直到遇到非可打印字符或字符串结束。

  2. 批量追加:通过记录可打印字符的起始位置和长度,使用sdscatlen(s, start, p - start);一次性将连续的可打印字符追加到字符串s中。这种方式减少了memcpy函数的调用次数,相比原始版本和预分配版本,进一步提高了可打印字符追加的效率,尤其在处理包含大量连续可打印字符的字符串时,性能提升更为显著。

4.2 优化效果

测试场景吞吐量(requests per second)平均延迟(msec)最小延迟(msec)50% 分位延迟(msec)95% 分位延迟(msec)99% 分位延迟(msec)最大延迟(msec)
优化前(无监控)714081.690.6540.1120.6870.8470.8793.247
优化前(1 个监控)332967.061.4490.3841.6471.8551.9274.263
优化后(无监控)714030.690.6450.1280.6710.8390.8712.839
优化后(1 个监控)395116.381.2210.2481.3671.5751.6313.735

通过对比可以发现,在有1个监控的场景下,优化后的版本吞吐量从332967.06/s提升至395116.38/s,提升幅度约为18%,且各分位延迟也有所改善,充分证明了批量处理可打印字符的优化策略对sdscatrepr函数性能提升的有效性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/86620.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/86620.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis 缓存机制详解

MyBatis 缓存机制详解 MyBatis 提供了强大的缓存机制来提高数据库访问性能,主要包括一级缓存和二级缓存两种。 一级缓存 (Local Cache) 特性: 默认开启,作用域为 SqlSession 级别同一个 SqlSession 中执行相同的 SQL 查询时,会…

设计模式精讲 Day 13:责任链模式(Chain of Responsibility Pattern)

【设计模式精讲 Day 13】责任链模式(Chain of Responsibility Pattern) 文章内容 在“设计模式精讲”系列的第13天,我们将深入讲解责任链模式(Chain of Responsibility Pattern)。这是一种行为型设计模式,…

h-ui面板 hysteria2

搭建文档 项目地址&#xff1a;https://github.com/jonssonyan/h-ui/blob/main/README_ZH.md参考视频&#xff1a;https://www.youtube.com/watch?vNi3iaLOsH_A一键部署命令 # root权限 sudo -ibash <(curl -fsSL https://raw.githubusercontent.com/jonssonyan/h-ui/mai…

自动登录脚本神器-Mac电脑实现自动登录堡垒机并自动输入账号密码跳转不同机器环境

先讲下背景&#xff1a; 公司电脑需要先登录堡垒机&#xff0c;然后再从堡垒机跳转到具体生产机器&#xff0c;每次输入堡垒机都要通过Authenticator里的2FC的码做验证&#xff0c;然后再跳到堡垒机还要再输入一次账号密码&#xff0c;为了方便快速登录机器&#xff0c;可以制…

【C/C++】C++26新特性前瞻:全面解析未来编程

展望未来&#xff1a;C26 新特性全面解析 随着 C 标准每三年一次的迭代节奏&#xff0c;C26&#xff08;预计于 2026 年底正式发布&#xff09;正在逐步成型。相比 C20 的革命性更新和 C23 的“修补增强”&#xff0c;C26 继续推进现代 C 的理念——更安全、更高效、更模块化&…

ArXiv 2101 | Rethinking Interactive Image Segmentation Feature Space Annotation

Rethinking Interactive Image Segmentation Feature Space Annotation Author: lartpangLink: https://github.com/lartpang/blog/issues/10论文&#xff1a;https://arxiv.org/abs/2101.04378代码&#xff1a;https://github.com/LIDS-UNICAMP/rethinking-interactive-image…

架构经验总结

20250511-总结经验 一、SOA 1&#xff09;过程&#xff1a;需求分析、系统设计、系统实现、构件组装、部署运维、后开发阶段。 2&#xff09;特点&#xff1a;无状态、单一职责、明确定义接口、自包含、模块化、粗粒度、重用性、兼容性、互操作性、松耦合、策略声明。 3&…

debain切换 opensuse 我都安装了什么

绿色进度条后&#xff0c;黑屏&#xff08;只有一个下划线&#xff09;等待 使用 nomodeset 属性解决 进入系统无法连接 wifi&#xff0c;只能使用网线连接 wifi 这个我在安装中文字体后&#xff0c;注销登录&#xff0c;得到了解决&#xff0c;不确定是不是字体问题。&#x…

思科ISE/ISE-PIC安全警报:两处高危RCE漏洞(CVSS 10.0)可致未授权获取root权限

思科已发布更新&#xff0c;修复身份服务引擎&#xff08;Identity Services Engine&#xff0c;ISE&#xff09;及ISE被动身份连接器&#xff08;ISE-PIC&#xff09;中两处最高危安全漏洞&#xff0c;这些漏洞可能允许未经认证的攻击者以root用户身份执行任意命令。 漏洞详情…

智能助手(利用GPT搭建智能系统)

项目介绍 本项目旨在打造一个基于通义千问模型的智能助手&#xff0c;能够理解用户指令并自动生成可执行的 JavaScript 代码。该代码可直接调用预设接口&#xff0c;完成指定操作&#xff0c;并返回执行结果。通过大模型的理解与生成能力&#xff0c;实现从自然语言到接口调用…

【源码+文档+调试讲解】基于web的运动健康小程序的设计与实现y196

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对高校教师成果信息管理混乱&#xff0c;出错率高&#xff0c;信息安全…

临床项目计划框架

一、项目概述 1.1 项目名称 项目名称:评估XX药物在YY患者中安全性和有效性的III期随机对照试验 1.2 项目背景与立项依据 1.2.1 研究背景 简述疾病负担、当前治疗现状、未满足的医疗需求,为项目开展提供背景支持。 1.2.2 科学依据 总结前期研究结果、理论基础、研究假设的形…

Hoare逻辑与分离逻辑:从程序验证到内存推理的演进

文章目录 引言一、Hoare逻辑基础&#xff1a;程序正确性的形式化验证&#x1f330; 例子&#xff1a;简单赋值语句的Hoare逻辑验证&#x1f330; 例子&#xff1a;条件语句的Hoare逻辑验证 二、分离逻辑&#xff1a;Hoare逻辑在内存管理中的扩展&#x1f50d; 分离逻辑的核心扩…

Tomcat Maven 插件

在 Maven 项目中&#xff0c;可以使用 Tomcat Maven 插件&#xff08;tomcat7-maven-plugin 或 tomcat-maven-plugin&#xff09;来直接部署 WAR 文件到 Tomcat 服务器&#xff0c;而无需手动复制 WAR 文件到 webapps 目录。以下是详细的使用方法&#xff1a; 1. 配置 Tomcat M…

【开源工具】一键解决使用代理后无法访问浏览器网页问题 - 基于PyQt5的智能代理开关工具开发全攻略

&#x1f310;【开源工具】一键解决使用代理后无法访问浏览器网页问题 - 基于PyQt5的智能代理开关工具开发全攻略 &#x1f308; 个人主页&#xff1a;创客白泽 - CSDN博客 &#x1f525; 系列专栏&#xff1a;&#x1f40d;《Python开源项目实战》 &#x1f4a1; 热爱不止于代…

异步IO框架io_uring实现TCP服务器

一、io_uring介绍 io_uring是 Linux 于 2019 年加入到内核的一种新型异步 I/O 模型&#xff0c;io_uring 主要为了解决 原生AIO&#xff08;Native AIO&#xff09; 存在的一些不足之处。下面介绍一下原生 AIO 的不足之处&#xff1a; 系统调用开销大&#xff1a;提交 I/O 操作…

【docker】docker run参数说明

功能 拉起容器。 参数 -i&#xff0c;--interactive 保持容器标准输入放开&#xff0c;就算没有终端也放开。 可以理解为可以向容器内输入东西&#xff0c;比如&#xff1a; [rootlocalhost ~]# echo 111 | docker run -i yaxin:1.0 cat 111--cap-add 用于向容器添加特定的…

从0开始学习计算机视觉--Day04--损失函数

在上次学习中&#xff0c;我们知道了线性分类的函数是f(x,W),但并没有解释要怎么得到W权重矩阵的值&#xff0c;以及我们要怎么用训练数据来确定它的最优权重矩阵。在之前我们知道&#xff0c;假设用了10种类别的图片用于训练&#xff0c;将其中一种图片输入模型后&#xff0c;…

【V2.0】TPS-61088升压板-3.7V升压到9V电源板

优化一下上一版本的升压板&#xff1a; TPS-61088升压板-3.7V升压到9V电源板-CSDN博客 改动参考了官方的demo板 加了很多的电容&#xff0c;封装很大&#xff0c;同时去掉了AGND&#xff0c;直接使用一个GND。 补偿电路增加了一个47pF的电容。 EN引脚改用输入的电压分压来启…

基于DeepSeek搭建Dify智能助手国产化架构运行arm64

基于DeepSeek搭建Dify智能助手国产化架构运行arm64 基于DeepSeek搭建Dify智能助手案例介绍案例内容1 概述1.1 背景介绍1.2 适用对象1.3 案例时间1.4 案例流程1.5 资源总览 2.启动 Docker 容器没有的安装2.1没有Docker安装 3 云主机部署DeepSeek3.1 安装Ollama 4.安装Dify4.1Doc…