simdjson:利用 SIMD 指令实现 GB/s 级 JSON 解析的 C++ 开源库

适用读者:刚入门 C++ 的开发者、被 JSON 解析速度困扰的后端工程师、一切对"每秒能吃掉多少条日志"有执念的人。 本文约定:所有示例代码基于 simdjson v3.x(向下兼容 v2.x 的 DOM 用法),要求 C++17 及以上。

1. 这库是什么:30 秒认识 simdjson

simdjson 是一个用 C++ 编写的高性能 JSON 解析库,核心卖点就一句话:

别人解析 JSON 的单位是"兆字节每秒(MB/s) ",它直接干到了"吉字节每秒(GB/s)",快了 10~50 倍。

为什么能做到?因为它在 CPU 层面用上了 SIMD(Single Instruction, Multiple Data,单指令多数据) 指令。普通程序处理 JSON 是一个字符一个字符"排队过安检",而 simdjson 让 CPU 一次指令同时检查 32 个字符,相当于把单通道安检口换成了 32 通道并行安检口。

打个比方:传统解析器像人工抄写员,一个字母一个字母地抄;simdjson 像一台高速扫描仪,一页纸"唰"地一下整页进,整页出。

注意定位 :我们之前写过一篇nlohmann/json 开源 JSON 库的博客,那是"通用易用派"的代表(功能全、写起来爽);而 simdjson 是"极致性能派"的代表(快、省内存、只读不写)。两者定位不同:nlohmann/json 是随身瑞士军刀,simdjson 是工业级传送带。本文主角是后者。


2. 开源背景:作者、协议、Star 量级

项目 说明
项目主页 github.com/simdjson/simdjson
主要作者 Daniel Lemire(加拿大魁北克大学教授,数据科学/高性能计算领域知名学者),核心贡献者还包括 John Keiser、Geoff Langdale 等
首次发布 2019 年(配套论文 Parsing gigabytes of JSON per second 发表于 VLDB Journal)
开源协议 Apache License 2.0(宽松商业友好,可自由商用、修改、分发)
Star 量级 20k+(截至 2026 年,长期位列 C++ 高性能库头部)
语言要求 C++17 及以上,纯头文件 + 少量源文件,跨平台(Windows / Linux / macOS / ARM)
官方性能 官方基准:在 4GHz Skylake(支持 AVX2)上解析 Twitter JSON 数据集可达 2.5+ GB/s

⚠️ Star 数是动态数据,写作时以 GitHub 页面实时为准;本文给出的量级用于说明"这是社区公认的主流高性能库"。

simdjson 的诞生背景很直接:JSON 已经成为互联网事实标准数据格式,但传统解析器(如 nlohmann/json、RapidJSON 的普通模式)在大量场景下只能跑到 100~400 MB/s。对"每秒钟要处理几 GB 日志"的团队来说,解析器就是瓶颈。Daniel Lemire 团队从 2016 年前后开始研究用 SIMD 加速 JSON 结构识别,最终产出了这个库。


3. 为什么要用:四大优点逐个拆解

3.1 优点一:SIMD 加速原理------让 CPU "一把抓"

第 1 步:理解 SIMD 是什么

普通 CPU 指令一次处理一个数据(比如一次读 1 个字节)。SIMD 指令(x86 上的 SSE/AVX2/AVX-512、ARM 上的 NEON)允许 CPU 一次加载 16/32/64 个字节到同一个"大寄存器"里,然后一条指令同时对它们做运算

类比:普通模式是"一个邮递员一次送一封信",AVX2 模式是"一个邮递员骑着三轮车一次送 32 封信"。

第 2 步:JSON 解析的瓶颈在哪里

解析 JSON 最耗时的工作,不是"读数字",而是扫描整段文本找结构符号

  1. 找 { } : , 这些"骨架符号"(structural character);
  2. 判断哪些引号是字符串的引号、哪些是转义 \" 的一部分(避免把字符串里的 : 误判成键值分隔符);
  3. 判断哪些空白可以被跳过。

传统解析器逐字节判断,if (c == '{' || c == '}' || ...) 一路比下去,遇到 1GB 文本就要做几十亿次单字节比较。

第 3 步:simdjson 怎么用 SIMD 加速

simdjson 的核心技巧(论文里叫 structural character identification)分三层:

  1. 一次处理 32/64 字节 :用 AVX2 一次加载 32 字节,用 _mm256_cmpeq_epi8(逐字节相等比较) 之类的指令,同时判断这 32 个字节里哪些是 {、哪些是 }......所有比较都在一条指令里完成,结果是一个 32 位的掩码(bitmask),每一位对应一个字节"是不是某类字符"。
  2. 多路并行比较合并:分别得到"是花括号的掩码""是方括号的掩码""是引号的掩码"等,再用位运算 OR 合并成一张"结构符号位图"。
  3. 快速跳过字符串与转义:字符串内部用 SIMD 找 " 和 \,一次跳过整个字符串内容,而不是逐字符走进字符串。

最终效果:无论 JSON 里有多少内容,识别结构符号的开销从"每字节若干条指令"降到"每 32 字节若干条指令",这就是数量级的差距来源。

小白类比:传统解析是"拿着放大镜逐字核对错别字",simdjson 是"整段文字用 OCR 扫描仪一次过"------扫描仪当然也有代价(要先凑齐 32 个字节),但吞吐量完胜。

3.2 优点二:GB/s 级性能------快到什么程度

官方与第三方基准普遍给出如下量级(数据源:simdjson 官方 README 及论文,Intel Skylake / Apple M1 等现代 CPU):

解析器 大致吞吐(4GHz x86) 说明
simdjson(AVX2) 2.5 ~ 3.5 GB/s 官方基准 Twitter JSON 数据集
RapidJSON(普通模式) ~300 MB/s 老牌高性能库,SIMD 支持有限
nlohmann/json ~100 ~ 200 MB/s 易用性王者,性能一般
各语言标准库 JSON 通常 < 500 MB/s 含 Python/JS 等解释型实现

换算成业务语言:1GB 的 JSON 日志,simdjson 大约 0.3~0.4 秒解析完,而 nlohmann/json 需要 5~10 秒。这就是"GB/s 级"的含义------不是"能解析 GB 大小的文件",而是"解析速度以 GB/s 计"。

性能还体现在内存分配极少:simdjson 解析过程几乎不产生临时字符串拷贝(见下一条),大幅减少 malloc/free 和 cache miss。

3.3 优点三:零拷贝 + 惰性解析------只看不搬

这是 simdjson 和传统 DOM 库最本质的设计差异,分两点:

1) 零拷贝(zero-copy)视图

传统 DOM 解析器(如 nlohmann/json)会复制数据:把 JSON 里的字符串 "name": "Alice" 复制进一个新的 std::string 对象,建一棵完全独立于原始文本的对象树。

simdjson 不这么做:它解析出的 dom::element 只是指向原始缓冲区的"视图"(相当于给原始文本贴了个标签:这里是一个字符串、那里是一个数字)。取值时它返回 std::string_view------一个"看得到这段文本但不拥有它"的轻量指针+长度。

好处:

  • 解析过程几乎不分配内存;
  • 取字符串零拷贝,直接看原始缓冲区。

代价(⚠️ 易错点):原始 JSON 缓冲区必须活得比解析结果久。如果你把 JSON 字符串局部变量销毁了再去读结果,就是悬空引用(use-after-free)。

2) 惰性解析(on-demand,按需惰性取值)

v2.0 起引入的 on-demand API 更进一步:你取哪个字段,它才解析哪个字段,而不是把整棵 JSON 树先建好。

类比:整棵 JSON 是一栋大楼,DOM API 是"先把整栋楼的房间钥匙全部配好给你";on-demand 是"你走到哪个房间门口,才现场开那把锁"。如果你只需要 100 个字段里的 2 个,on-demand 能省掉大约 90% 的解析工作量。

3.4 优点四:易用 API------简单到像读字典

虽然底层用 SIMD 很"硬核",但对外 API 非常友好,两行就能解析:

cpp 复制代码
simdjson::dom::parser parser;                       // 创建一个解析器(可复用)
simdjson::dom::element doc = parser.parse(json);    // 解析 JSON,得到根元素
std::string_view name = doc["name"];                // 像字典一样取值

配合 simdjson_result(带错误码的结果类型),出错时不用捕获异常,直接 if (!result) { ... } 判断即可,既安全又高效。

3.5 与 nlohmann/json 的对比表格

维度 simdjson nlohmann/json
定位 极致性能的只读解析器 通用易用、功能全面的 JSON 库
解析速度 GB/s 级(快 10~50 倍) 100~200 MB/s 量级
底层技术 SIMD(AVX2/AVX-512/NEON)+ 零拷贝视图 传统逐字符 + 内存复制建树
字符串取值 std::string_view(零拷贝) std::string(复制)
惰性解析 ✅ on-demand API 按需解析 ❌ 必须整体建 DOM 树
修改/生成 JSON ❌ 只读(可 minify,不能改树) ✅ 支持增删改查、序列化输出
任意精度/自定义类型 ❌ 有限 ✅ 支持自定义类型转换
错误处理 错误码 simdjson_result(可选异常) 默认抛异常
数据所有权要求 ⚠️ 原始缓冲区须长于结果 不要求(数据已复制)
学习成本 中(需理解视图生命周期) 低(上手极快)
适用场景 高频读、大吞吐、日志/网关/管道 通用业务、CRUD、需要写 JSON 的场景

结论一句话:只读、量大、追求吞吐 → simdjson;要写、要改、图省事 → nlohmann/json。两者也可以混用:simdjson 读出来,转成 nlohmann 对象再往业务层传。


4. 典型使用场景:哪些项目应该选它

场景 为什么适合 simdjson 典型形态
日志分析 海量 NDJSON(每行一条 JSON)持续灌入,parse_many 流式处理,吞吐决定一切 日志采集、ELK 前置解析、告警规则匹配
大数据管道(ETL) 每批几 GB JSON 要快速清洗、提取字段、写入下游 数据湖入湖、实时数仓、特征提取
API 网关 / 反向代理 每个请求都要解析 JSON 做路由/鉴权/限流,解析时间是关键延迟 网关中间件、BFF 层、请求改写
实时数据流 行情、IoT 遥测、监控指标,每秒成千上万条 JSON 行情推送、设备上报、指标聚合
数据库/缓存层 存储引擎内部要把 JSON 当"可查询文档",读多写少 文档型扩展、JSONB 前置解析
桌面/嵌入式工具 只需快速读取配置或数据文件,希望零拷贝省内存 配置文件解析、离线分析工具

不适合:需要频繁修改 JSON 结构、需要把对象重新序列化成 JSON 输出、解析次数很少而开发效率优先的小工具------这些请继续用 nlohmann/json 或 RapidJSON。


5. 快速上手:从零到跑通(分步教程)

第 1 步:准备编译环境

  • 编译器:支持 C++17 的 GCC 7+ / Clang 5+ / MSVC 2019+(Windows 建议 VS2019 或更高)。
  • CMake:3.15+。
  • CPU:无需手动开启 SIMD!simdjson 默认运行时自动检测(runtime dispatch),在支持 AVX2/NEON 的机器上自动用最快路径;当然,想榨干性能也可以编译期指定 -march=native(见第 7 节)。

⚠️ 不需要手动 #include <immintrin.h> 或写任何 SIMD 代码,库内部已封装好。

第 2 步:用 CMake 集成 simdjson

推荐 FetchContent 方式,一条命令拉取并编译(无需提前安装):

cpp 复制代码
cmake_minimum_required(VERSION 3.15)
project(simdjson_demo CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 1. 从 GitHub 拉取 simdjson 源码(可换成 tag 或 commit 固定版本)
include(FetchContent)
FetchContent_Declare(
  simdjson
  GIT_REPOSITORY https://github.com/simdjson/simdjson.git
  GIT_TAG        v3.12.0          # 建议固定版本,避免上游变动
)
FetchContent_MakeAvailable(simdjson)

add_executable(simdjson_demo main.cpp)

# 2. 链接 simdjson(CMake 会自动处理编译参数与运行时分发)
target_link_libraries(simdjson_demo PRIVATE simdjson)

如果你已通过包管理器(vcpkg / Conan)或系统安装 simdjson,也可以用更轻量的方式:

复制代码
find_package(simdjson REQUIRED)
target_link_libraries(simdjson_demo PRIVATE simdjson::simdjson)

第 3 步:写第一段解析代码

创建 main.cpp:

cpp 复制代码
#include <iostream>
#include <string>
#include <simdjson.h>        // 只需包含这一个头文件

int main() {
    // 1. 准备一段 JSON 文本(注意:simdjson 要求输入是完整合法的 JSON)
    std::string json = R"({
        "service": "auth",
        "status": "ok",
        "latency_ms": 12
    })";

    // 2. 创建解析器(可复用,不要每解析一次就新建)
    simdjson::dom::parser parser;

    // 3. 解析!parser.parse 返回 simdjson_result,可直接当 bool 判断
    simdjson::dom::element doc = parser.parse(json);
    if (doc.error()) {                          // 出错时 error() 返回错误码对象
        std::cerr << "解析失败: " << simdjson::error_message(doc.error()) << std::endl;
        return 1;
    }

    // 4. 像字典一样取值:operator[] 支持整数下标和字符串键
    std::string_view service = doc["service"];   // 返回 string_view(零拷贝!)
    std::string_view status  = doc["status"];
    int64_t latency = doc["latency_ms"];         // 数字可隐式转换为 int64_t

    // 5. 输出
    std::cout << "service  = " << service << std::endl;
    std::cout << "status   = " << status  << std::endl;
    std::cout << "latency  = " << latency << " ms" << std::endl;
    return 0;
}

第 4 步:编译并运行

bash 复制代码
# 在 CMake 工程根目录
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
./build/simdjson_demo

预期输出:

复制代码
service  = auth
status   = ok
latency  = 12 ms

⚠️ 必须用 Release 模式!Debug 模式(-O0)下 SIMD 内联优化被关闭,性能会退化到和普通库差不多,甚至更慢。


6. 核心用法详解(可运行代码)

下面每个小节都给出可直接运行的示例。为节约篇幅,示例共用同一个解析器声明,实际使用时请把代码放进同一个文件或按需合并。

6.1 DOM API:传统的一次性解析

DOM(Document Object Model,文档对象模型)是"先把整棵树建好,再随便查"的经典模式。适合同一份 JSON 会被反复读取多次的场景。

cpp 复制代码
#include <iostream>
#include <string>
#include <simdjson.h>

int main() {
    std::string json = R"({
        "users": [
            {"id": 1, "name": "Alice", "tags": ["admin", "c++"]},
            {"id": 2, "name": "Bob",   "tags": ["dev"]}
        ],
        "total": 2
    })";

    simdjson::dom::parser parser;
    simdjson::dom::element doc = parser.parse(json);
    if (doc.error()) {
        std::cerr << "解析失败: " << simdjson::error_message(doc.error()) << std::endl;
        return 1;
    }

    // 1. 取数组
    simdjson::dom::array users = doc["users"];

    // 2. 遍历数组,取每个对象的字段
    for (simdjson::dom::element user : users) {
        int64_t id   = user["id"];
        std::string_view name = user["name"];
        std::cout << "id=" << id << ", name=" << name << std::endl;

        // 3. 嵌套数组
        simdjson::dom::array tags = user["tags"];
        for (std::string_view tag : tags) {   // 数组元素是字符串,可直接转 string_view
            std::cout << "    tag: " << tag << std::endl;
        }
    }

    // 4. 取根对象的另一个字段
    std::cout << "total=" << doc["total"].get_int64() << std::endl;
    return 0;
}

关键 API 速查:

表达式 含义
parser.parse(json) 解析 JSON,返回根元素
doc"key" 按字符串键取值
arr.at(0) / arri 按下标取数组元素
element.get_int64() / get_double() 显式取数字
element.get_string() 显式取字符串(返回 std::string_view)
element.is_object() / is_array() / is_null() 类型判断
element"a""b" 链式取嵌套字段

6.2 on-demand:按需惰性取值

on-demand (按需惰性)是 simdjson 官方推荐的默认路径:访问到哪个字段,才解析哪个字段。适合"JSON 很大,但我只关心其中几个字段"的场景。

cpp 复制代码
#include <iostream>
#include <string>
#include <simdjson.h>

int main() {
    std::string json = R"({
        "header": {"request_id": "abc-123", "timestamp": 1723000000},
        "payload": {"data": "这里有一大堆用不到的数据..."}
    })";

    // on-demand 使用独立的解析器类型
    simdjson::ondemand::parser parser;

    // iterate() 不是立即解析,而是创建一个惰性迭代器(JSON 数据需存活到读取完成)
    simdjson::ondemand::document doc = parser.iterate(json);
    if (doc.error()) {
        std::cerr << "解析失败: " << simdjson::error_message(doc.error()) << std::endl;
        return 1;
    }

    // 只取我们关心的字段------其余部分(payload)根本不会被解析
    std::string_view request_id = doc["header"]["request_id"];
    int64_t ts = doc["header"]["timestamp"];

    std::cout << "request_id=" << request_id << std::endl;
    std::cout << "timestamp =" << ts << std::endl;
    return 0;
}

⚠️ on-demand 是单遍读取模型:同一路径的 doc"header" 不能反复取(除非重新 iterate)。如果需要反复读,请用 DOM API。另外,on-demand 的惰性意味着某些错误(如字段类型不匹配)会在"取值那一刻"才暴露,而不是 parse 时。

6.3 流式解析 parse_many:一行一条(NDJSON)

日志、事件流最常见的格式是 NDJSON(Newline-Delimited JSON,每行一条 JSON)。用 parse_many 可以流式处理,不用等整个文件读完:

cpp 复制代码
#include <iostream>
#include <string>
#include <simdjson.h>

int main() {
    // 模拟 3 行 NDJSON(末尾不要漏换行,parse_many 需要靠它切分)
    std::string ndjson = R"({"level":"INFO","msg":"started"}
{"level":"ERROR","msg":"disk full"}
{"level":"WARN","msg":"retry"}
)";

    simdjson::dom::parser parser;
    simdjson::dom::document_stream docs = parser.parse_many(ndjson);

    // 遍历每一行 JSON
    for (simdjson::dom::element doc : docs) {
        if (doc.error()) {
            std::cerr << "某行解析失败: " << simdjson::error_message(doc.error()) << std::endl;
            continue;
        }
        std::string_view level = doc["level"];
        std::string_view msg   = doc["msg"];
        std::cout << "[" << level << "] " << msg << std::endl;
    }
    return 0;
}

⚠️ parse_many 要求输入以换行符分隔且末尾有换行;文件太大时可用 parse_many(json, batch_size) 指定批大小控制内存。

6.4 minify:把 JSON 压到最小

minify 会去掉 JSON 中所有可有可无的空白(空格、换行、制表符),常用于减少存储和网络传输体积:

cpp 复制代码
#include <iostream>
#include <string>
#include <simdjson.h>

int main() {
    std::string pretty_json = R"({
        "name" : "simdjson",
        "stars" : 20000
    })";

    // minify 直接原地压缩(第二个参数是输出缓冲,需预留空间)
    std::string compact;
    compact.resize(pretty_json.size());        // 压缩结果不会比原文更长,预留即可
    size_t written = simdjson::minify(pretty_json, compact.data());
    compact.resize(written);                    // 截断到实际写入长度

    std::cout << "压缩前: " << pretty_json.size() << " 字节" << std::endl;
    std::cout << "压缩后: " << compact.size() << " 字节" << std::endl;
    std::cout << compact << std::endl;
    return 0;
}

⚠️ minify 不会删除字符串内部的空格,例如 "hello world" 里的空格是数据的一部分,必须保留。

6.5 JSON Pointer:按路径精准取值

JSON Pointer(RFC 6901)用 / 分隔的路径字符串定位深层字段,适合"路径来自配置或外部输入"的场景:

cpp 复制代码
#include <iostream>
#include <string>
#include <simdjson.h>

int main() {
    std::string json = R"({
        "api": {
            "v1": {
                "endpoints": ["/login", "/logout"],
                "timeout_ms": 5000
            }
        }
    })";

    simdjson::dom::parser parser;
    simdjson::dom::element doc = parser.parse(json);
    if (doc.error()) return 1;

    // at_pointer 使用 JSON Pointer 语法:/根键/子键/数组下标
    std::string_view endpoint = doc.at_pointer("/api/v1/endpoints/0");
    int64_t timeout = doc.at_pointer("/api/v1/timeout_ms");

    std::cout << "endpoint=" << endpoint << std::endl;
    std::cout << "timeout =" << timeout << " ms" << std::endl;
    return 0;
}

等价写法:doc"api""v1""endpoints"0。JSON Pointer 的优势是路径可以动态拼接,比如 std::string path = "/api/" + version + "/endpoints/0"。

6.6 错误处理:不抛异常的代价

simdjson 默认不抛异常,所有可能失败的操作都返回 simdjson_result<T>。检查错误有两种方式:

cpp 复制代码
#include <iostream>
#include <string>
#include <simdjson.h>

int main() {
    std::string bad_json = R"({"name": "Alice", )";   // 故意缺右括号

    simdjson::dom::parser parser;

    // 方式一:用 .error() 判断(推荐)
    simdjson::dom::element doc = parser.parse(bad_json);
    if (doc.error()) {
        std::cout << "方式一捕获错误: "
                  << simdjson::error_message(doc.error()) << std::endl;
        return 0;
    }

    // 方式二:直接把结果当 bool 用(simdjson_result 重载了 operator bool)
    // simdjson::dom::element doc2 = parser.parse(bad_json);
    // if (!doc2) { ... }
    return 0;
}

如果你更喜欢异常风格,可以在编译时定义 SIMDJSON_EXCEPTIONS=ON,然后直接写 simdjson::dom::element doc = parser.parse(json);,出错时库会抛 simdjson_error。

⚠️ 不要忽略错误返回值!解析失败时元素内容是未定义的,继续使用会得到垃圾数据。


7. 易错点与性能调优清单

易错点 / 调优点 说明
1 ⚠️ 原始缓冲区生命周期 零拷贝意味着解析结果引用原文本。请确保 JSON 字符串存活到所有取值结束。
2 ⚠️ 必须 Release 编译 Debug 模式关闭优化,SIMD 内联失效,性能骤降。
3 ⚠️ 不要复用同一 DOM 元素跨多次 parse parser.parse() 会复用内部缓冲区,旧元素视图可能失效;需要保留就复制或改用 on-demand 重新 iterate。
4 ⚠️ on-demand 是单遍读取 同一路径不可重复取;需反复读请用 DOM。
5 ⚠️ parse_many 末尾要有换行 否则最后一条可能解析不出来或报错。
6 解析器复用 一个 parser 反复 parse(),比每次 new 一个快得多(复用内部缓冲区)。
7 开启 CPU 原生指令集 编译加 -march=native(GCC/Clang)或 /arch:AVX2(MSVC)可让 SIMD 路径固定为最强;注意换机器部署时可能不兼容,生产建议保留运行时自动检测。
8 按需取用,别整树搬运 大 JSON 只取少数字段时用 on-demand;全部字段都要且反复读时用 DOM。
9 优先 std::string_view 取值尽量保留 string_view,不要立刻转 std::string(会触发拷贝)。
10 大文件分批 超大文件用 parse_many(json, batch_size) 或 mmap 后分段解析,控制峰值内存。

8. FAQ 速查表

问题 速答
simdjson 要装什么依赖? 零第三方依赖,只有 C++17 编译器 + CMake。
我需要在代码里写 SIMD 吗? 不需要,库内部自动处理,默认运行时自动检测指令集。
为什么比我手写的解析器快这么多? 一次处理 32/64 字节 + 零拷贝视图 + 惰性解析,三层优化叠加。
simdjson 能修改 JSON 吗? 不能修改 DOM 树;只能读取、minify。要修改请用 nlohmann/json。
和 nlohmann/json 怎么选? 只读+大吞吐 → simdjson;读写都要/图省事 → nlohmann/json。
解析结果能保存到下次再用吗? DOM 元素跨 parse 会失效;长期保存请复制数据或转成自己的结构。
on-demand 和 DOM 有什么区别? on-demand 用到才解析(快、省内存、单遍);DOM 一次建全树(可反复读)。
支持 JSON 里的大数字(超过 int64)吗? 数字以 int64/double 为主,超大整数需自己按字符串取(get_raw_json_number)。
支持 Windows 吗? 支持 MSVC 2019+;同样自动选择 SSE4/AVX2 路径。
出错会崩吗? 不会,默认返回错误码;可选开启异常模式。

9. 参考资料

相关推荐
A_nanda1 小时前
c#WPF开发常见问题
开发语言·c#·wpf
Hello.Reader1 小时前
REALITY 技术深度解析从 TLS 伪装、抗主动探测到 VLESS + XTLS Vision 完整实践
开发语言·php
不正经学生1 小时前
C语言字符串函数进阶:安全版函数 + 错误处理 + 子串查找
c语言·开发语言·c++·算法·面试
ITKEY_2 小时前
neovim基于nvim-jdtls 开发java报错
java·开发语言
無限進步D2 小时前
Java 代码块
java·开发语言
吃好睡好便好2 小时前
MATLAB仿真框图4
开发语言·matlab·仿真·分段函数
三克的油2 小时前
算法基础-1
数据结构·c++·算法
TheBestRucy2 小时前
基于Dify的旅游攻略&王者荣耀攻略智能助手项目
服务器·开发语言·人工智能·python·算法·旅游
一水2 小时前
Pi :内置四工具源码拆解——文件锁、变更快照与 bash 隔离
开发语言·chrome·ai·bash