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
英文地址,請注明出處:http://en.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…