内省排序:相对最迅速的通用排序算法

🔍 内省排序:相对最迅速的通用排序算法

🚀 前言:排序算法的演进之路

排序算法是计算机科学的核心基础之一,其性能直接影响着数据库系统、科学计算、图形渲染等领域的效率。随着硬件架构的发展,排序算法经历了从简单到复杂的演化过程:

基础算法
分治算法
混合算法
硬件优化算法
自适应算法

在众多排序算法中,内省排序(Introsort) 作为目前公认最快的通用排序算法,被广泛应用于C++标准库实现中。本文将深入解析内省排序的原理、实现细节及优化策略,并通过实验数据展示如何超越标准库实现。

🧠 一、算法核心原理与架构剖析

1.1 内省排序的设计哲学

内省排序是David Musser于1997年提出的混合排序算法,结合了三种经典算法的优势:

  • 快速排序:平均O(n log n)时间复杂度
  • 堆排序:保证最坏情况O(n log n)时间复杂度
  • 插入排序:小数据集上的高效表现

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/538cad930352435982daf43ddfc42df1.png

1.2 时间复杂度与空间复杂度分析

算法最佳平均最坏空间
快速排序O(n log n)O(n log n)O(n²)O(log n)
堆排序O(n log n)O(n log n)O(n log n)O(1)
插入排序O(n)O(n²)O(n²)O(1)
内省排序O(n)O(n log n)O(n log n)O(log n)

内省排序的关键创新在于动态监控递归深度,当超过2*log₂(n)时切换到堆排序,避免快速排序的最坏情况。

1.3 标准库实现的优势与局限

C++标准库的std::sort采用内省排序,但具有独特优势:

  • 编译器内在优化:使用__builtin_expect等指令优化分支预测
  • 平台特定优化:针对不同CPU架构的指令集优化
  • 内存访问优化:精细控制缓存行为

然而,标准库实现也有其局限性:

  • 固定阈值策略:插入排序和堆排序的切换阈值固定
  • 通用性优先:为各种数据类型优化,牺牲了整数排序的特化性能
  • 保守优化策略:避免使用最新指令集以保证兼容性

⚙️ 二、关键优化技术深度解析

2.1 分区算法的演进与优化

2.1.1 基础分区算法
// 经典Lomuto分区方案
int partition(vector<int>& arr, int low, int high) {int pivot = arr[high];int i = low - 1;for (int j = low; j < high; j++) {if (arr[j] <= pivot) {i++;swap(arr[i], arr[j]);}}swap(arr[i+1], arr[high]);return i+1;
}
2.1.2 三数取中优化
// 改进的枢轴选择策略
int median_of_three(int a, int b, int c) {if (a < b) {if (b < c) return b;       // a < b < celse if (a < c) return c;  // a < c ≤ belse return a;             // c ≤ a < b} else {if (a < c) return a;       // b ≤ a < celse if (b < c) return c;  // b < c ≤ aelse return b;             // c ≤ b ≤ a}
}
2.1.3 AVX向量化分区
// 使用AVX指令集加速分区过程
int partition_avx(vector<int>& arr, int low, int high) {// ... 三数取中选择枢轴 ...__m256i pivot_vec = _mm256_set1_epi32(pivot);int* data = arr.data();for (; j <= high - 8; j += 8) {__m256i elements = _mm256_loadu_si256((__m256i*)&data[j]);__m256i cmp = _mm256_cmpgt_epi32(pivot_vec, elements);int mask = _mm256_movemask_ps(_mm256_castsi256_ps(cmp));// 处理比较结果for (int k = 0; k < 8; k++) {if (mask & (1 << k)) {i++;swap(data[i], data[j + k]);}}}// ... 处理剩余元素 ...
}

AVX分区的性能优势来自:

  1. 并行比较:单次处理8个元素
  2. 减少分支:使用掩码替代条件分支
  3. 向量化操作:利用SIMD寄存器高效处理数据

2.2 递归消除与迭代优化

递归调用会导致函数调用开销和栈空间消耗,内省排序通过迭代实现消除递归:

void quick_sort_iterative(vector<int>& arr, int low, int high) {stack<pair<int, int>> stk;stk.push({low, high});while (!stk.empty()) {tie(low, high) = stk.top();stk.pop();if (high - low < THRESHOLD) {insertion_sort(arr.data(), low, high);continue;}int pi = partition(arr, low, high);// 优先处理较小分区以控制栈深度if (pi - low < high - pi) {if (low < pi - 1) stk.push({low, pi - 1});if (pi + 1 < high) stk.push({pi + 1, high});} else {if (pi + 1 < high) stk.push({pi + 1, high});if (low < pi - 1) stk.push({low, pi - 1});}}
}

2.3 阈值调优的艺术

阈值选择对性能有决定性影响:

小数据集
小阈值
大数据集
大阈值
CPU缓存
缓存行对齐
数据类型
比较成本

实验数据显示:

  • 32阈值:在50万数据量以下表现优异
  • 512阈值:在500万数据量以上超越标准库

📊 三、性能对比与实验分析

3.1 测试环境与方法论

  • 硬件:AMD R9-7945HX (16P+16L), 32*2GB DDR5 5600MHz
  • 编译器:Microsoft Visual Studio 2022, /O2优化
  • 数据集:随机整数数组,均匀分布
  • 测试方法:5次运行取平均值,排除缓存预热影响

3.2 关键性能数据对比

3.2.1 阈值32的性能表现(单位:ms)
数据量普通快排AVX快排内省排序标准库内省/标准库
100K4.423.573.523.990.88
500K31.5818.0217.7818.660.95
1M85.6037.3036.2236.041.00
5M1299.88267.44242.61171.481.41
3.2.2 阈值512的性能表现(单位:ms)
数据量普通快排AVX快排内省排序标准库内省/标准库
100K4.344.765.993.941.52
500K31.4926.4630.6918.601.65
1M86.1651.7558.1235.811.62
5M1299.02153.88153.14180.690.85

3.3 关键发现与洞见

  1. 小数据集优势

    • 32阈值内省排序在50万数据量内超越标准库
    • 优势来自优化的插入排序和更少的函数调用
  2. 大数据集反转

    • 5M数据量时,512阈值内省排序性能优于标准库15%
    • 主要来自AVX加速和优化的阈值策略
  3. AVX的边界效应

    数据量 < 100K
    AVX开销 > 收益
    100K < 数据量 < 1M
    显著加速
    数据量 > 1M
    线性加速
  4. 内存访问模式

    • 标准库在5M数据量仍有优势,源于优化的缓存策略
    • 自定义实现可通过调整内存布局进一步优化

🎯 四、各算法适用场景与策略指南

4.1 算法特性对比矩阵

特性普通快排AVX快排内省排序标准库
最佳数据量10K-100K100K-1M全范围全范围
最坏时间复杂度O(n²)O(n²)O(n log n)O(n log n)
平台依赖性x86/AVX
实现复杂度封装
小数据集性能★★☆★★☆★★★★★☆
大数据集性能★☆☆★★☆★★★★★☆
可调优性

4.2 实用决策树

< 50K
50K-500K
> 500K
选择排序算法
数据规模
平台支持AVX?
32阈值内省+AVX
32阈值内省
标准库
需要最优化?
512阈值内省+AVX
标准库

4.3 各场景最佳实践

  1. 嵌入式系统

    • 使用纯插入排序或小阈值内省排序
    • 避免AVX依赖和递归
  2. 科学计算

    • 512阈值内省排序+AVX加速
    • 数据预处理确保内存对齐
  3. 数据库系统

    • 标准库为主,特定模块定制
    • 混合使用不同阈值策略
  4. 游戏开发

    • 小数据使用32阈值内省
    • 大数据使用标准库

🚀 五、超越标准库的优化策略

5.1 动态阈值调整

实验显示固定阈值存在局限,实现动态阈值策略:

int dynamic_threshold(size_t n) {// 基于数据量和缓存大小计算阈值const size_t L1_cache_size = 32768; // 32KBconst size_t elem_size = sizeof(int);const size_t elems_in_cache = L1_cache_size / elem_size;if (n < 50000) return 32;else if (n < 1000000) return 64;else return min(512, static_cast<int>(elems_in_cache / 4));
}

5.2 混合内存布局

优化内存访问模式提升缓存利用率:

小数据集
大数据集
原始数据
数据规模
连续存储
分块存储
块内排序
多路归并

5.3 多核并行扩展

void parallel_intro_sort(vector<int>& arr) {const size_t threshold = 1000000;if (arr.size() < threshold) {intro_sort(arr);return;}unsigned conc_threads = thread::hardware_concurrency();vector<future<void>> futures;vector<vector<int>> segments(conc_threads);// 数据划分size_t seg_size = arr.size() / conc_threads;for (int i = 0; i < conc_threads; ++i) {auto begin = arr.begin() + i * seg_size;auto end = (i == conc_threads - 1) ? arr.end() : begin + seg_size;segments[i] = vector<int>(begin, end);futures.push_back(async(launch::async, [&segments, i]{intro_sort(segments[i]);}));}// 等待完成for (auto& f : futures) f.wait();// 多路归并// ... 高效合并已排序段 ...
}

📌 结论与工程建议

  1. 标准库优先原则

    • 大多数场景优先使用std::sort
    • 避免过早优化
  2. 定制化场景

    • 50万以下数据:32阈值内省排序
    • 500万以上数据:512阈值+AVX内省排序
    • 特定硬件:深度优化AVX/NEON实现
  3. 持续性能分析

    真实负载
    性能剖析
    热点分析
    算法优化
    参数调整
    部署验证
  4. 全栈优化思维

    • 算法选择与数据预处理结合
    • 内存布局与算法协同设计
    • 硬件特性充分挖掘

🧩 附录一:算法实机性能测试

内省排序阈值: 32

在这里插入图片描述

内省排序阈值: 512

在这里插入图片描述

🧩 附录二:完整算法实现及例程代码

#include <iostream>
#include <vector>
#include <random>
#include <chrono>
#include <algorithm>
#include <immintrin.h>
#include <cmath>
#include <stack>
#include <tuple>
#include <iomanip>using namespace std;
using namespace std::chrono;// 插入排序 - 使用指针减少索引计算
void insertion_sort(int* arr, int low, int high) {for (int i = low + 1; i <= high; i++) {int key = arr[i];int j = i - 1;// 使用指针算术int* p = arr + j;while (j >= low && *p > key) {*(p + 1) = *p;j--;p--;}*(p + 1) = key;}
}// 三数取中法选择枢轴
inline int median_of_three(int a, int b, int c) {if (a < b) {if (b < c) return b;else if (a < c) return c;else return a;}else {if (a < c) return a;else if (b < c) return c;else return b;}
}// 普通快速排序分区函数
int partition_normal(vector<int>& arr, int low, int high) {// 使用三数取中法选择枢轴int mid = low + (high - low) / 2;int pivot = median_of_three(arr[low], arr[mid], arr[high]);// 将枢轴放到最后if (pivot == arr[low])swap(arr[low], arr[high]);else if (pivot == arr[mid])swap(arr[mid], arr[high]);int i = low - 1;int* data = arr.data();// 使用指针算术循环for (int j = low; j < high; j++) {if (data[j] <= pivot) {i++;swap(data[i], data[j]);}}swap(data[i + 1], data[high]);return i + 1;
}// 普通快速排序 - 使用迭代代替递归减少函数调用开销
void quick_sort_normal_iterative(vector<int>& arr, int low, int high) {stack<pair<int, int>> stk;stk.push({ low, high });while (!stk.empty()) {tie(low, high) = stk.top();stk.pop();if (high - low < 16) {insertion_sort(arr.data(), low, high);continue;}int pi = partition_normal(arr, low, high);// 先处理较小的子数组以减少栈深度if (pi - low < high - pi) {if (low < pi - 1) stk.push({ low, pi - 1 });if (pi + 1 < high) stk.push({ pi + 1, high });}else {if (pi + 1 < high) stk.push({ pi + 1, high });if (low < pi - 1) stk.push({ low, pi - 1 });}}
}// AVX分区函数 - 减少内存访问和分支
int partition_avx(vector<int>& arr, int low, int high) {// 使用三数取中法选择枢轴int mid = low + (high - low) / 2;int pivot = median_of_three(arr[low], arr[mid], arr[high]);// 将枢轴放到最后if (pivot == arr[low])swap(arr[low], arr[high]);else if (pivot == arr[mid])swap(arr[mid], arr[high]);int i = low - 1;int j = low;const int simd_width = 8;int* data = arr.data();// 预加载枢轴值__m256i pivot_vec = _mm256_set1_epi32(pivot);// 处理可以对齐SIMD宽度的部分for (; j <= high - simd_width; j += simd_width) {// 非对齐加载数据__m256i elements = _mm256_loadu_si256((__m256i*) & data[j]);// 比较: elements <= pivot__m256i cmp = _mm256_cmpgt_epi32(pivot_vec, elements);int mask = _mm256_movemask_ps(_mm256_castsi256_ps(cmp));// 处理比较结果for (int k = 0; k < simd_width; k++) {if (mask & (1 << k)) {i++;swap(data[i], data[j + k]);}}}// 处理剩余元素for (; j < high; j++) {if (data[j] <= pivot) {i++;swap(data[i], data[j]);}}// 将枢轴放到正确位置swap(data[i + 1], data[high]);return i + 1;
}// AVX快速排序 - 使用迭代实现
void quick_sort_avx_iterative(vector<int>& arr, int low, int high) {stack<pair<int, int>> stk;stk.push({ low, high });while (!stk.empty()) {tie(low, high) = stk.top();stk.pop();if (high - low < 32) {  // 使用更大的阈值insertion_sort(arr.data(), low, high);continue;}int pi = partition_avx(arr, low, high);// 先处理较小的子数组以减少栈深度if (pi - low < high - pi) {if (low < pi - 1) stk.push({ low, pi - 1 });if (pi + 1 < high) stk.push({ pi + 1, high });}else {if (pi + 1 < high) stk.push({ pi + 1, high });if (low < pi - 1) stk.push({ low, pi - 1 });}}
}// 内省排序实现
void intro_sort(vector<int>& arr, int low, int high, int depth_limit) {// 如果数组很小,使用插入排序if (high - low < 32) {insertion_sort(arr.data(), low, high);return;}// 如果递归深度达到限制,使用堆排序if (depth_limit == 0) {make_heap(arr.begin() + low, arr.begin() + high + 1);sort_heap(arr.begin() + low, arr.begin() + high + 1);return;}// 使用的AVX分区int pi = partition_avx(arr, low, high);intro_sort(arr, low, pi - 1, depth_limit - 1);intro_sort(arr, pi + 1, high, depth_limit - 1);
}// 内省排序入口函数
void intro_sort(vector<int>& arr) {int n = arr.size();if (n <= 1) return;// 计算最大递归深度为2*log极(n)int depth_limit = static_cast<int>(2 * log2(n));intro_sort(arr, 0, n - 1, depth_limit);
}// 生成随机测试数据 - 使用更高效的方法
vector<int> generate_random_data(size_t size, int min_val = 0, int max_val = 10000) {vector<int> data(size);random_device rd;mt19937 gen(rd());uniform_int_distribution<> dis(min_val, max_val);// 使用指针算术循环int* data_ptr = data.data();for (size_t i = 0; i < size; i++) {data_ptr[i] = dis(gen);}return data;
}// 验证两个数组是否相同 - 使用memcmp
bool verify_equality(const vector<int>& arr1, const vector<int>& arr2) {if (arr1.size() != arr2.size()) return false;return memcmp(arr1.data(), arr2.data(), arr1.size() * sizeof(int)) == 0;
}// 性能测试函数
void performance_test(size_t data_size, int num_tests = 5) {cout << "数据量: " << data_size << " 元素" << endl;cout << "测试次数: " << num_tests << endl;cout << "==========================================" << endl;double normal_total_time = 0.0;double avx_total_time = 0.0;double intro_total_time = 0.0;double std_total_time = 0.0;// 表头cout << left << setw(8) << "测试"<< setw(15) << "普通(ms)"<< setw(15) << "AVX(ms)"<< setw(15) << "内省(ms)"<< setw(15) << "标准库(ms)"<< setw(15) << "AVX/普通"<< setw(15) << "内省/普通"<< setw(15) << "标准库/普通"<< setw(15) << "AVX/标准库"<< setw(15) << "内省/标准库"<< setw(20) << "性能排名" << endl;cout << "------------------------------------------------------------------------------------------------------------------------------------------------------------------------" << endl;for (int i = 0; i < num_tests; i++) {// 生成测试数据vector<int> data_normal = generate_random_data(data_size);vector<int> data_avx = data_normal;vector<int> data_intro = data_normal;vector<int> data_std = data_normal;// 测试标准库排序auto start = high_resolution_clock::now();sort(data_std.begin(), data_std.end());auto end = high_resolution_clock::now();double std_time = duration_cast<microseconds>(end - start).count() / 1000.0;std_total_time += std_time;// 测试普通快速排序start = high_resolution_clock::now();quick_sort_normal_iterative(data_normal, 0, data_size - 1);end = high_resolution_clock::now();double normal_time = duration_cast<microseconds>(end - start).count() / 1000.0;normal_total_time += normal_time;// 测试AVX快速排序start = high_resolution_clock::now();quick_sort_avx_iterative(data_avx, 0, data_size - 1);end = high_resolution_clock::now();double avx_time = duration_cast<microseconds>(end - start).count() / 1000.0;avx_total_time += avx_time;// 测试内省排序start = high_resolution_clock::now();intro_sort(data_intro);end = high_resolution_clock::now();double intro_time = duration_cast<microseconds>(end - start).count() / 1000.0;intro_total_time += intro_time;// 验证结果正确性bool normal_correct = verify_equality(data_normal, data_std);bool avx_correct = verify_equality(data_avx, data_std);bool intro_correct = verify_equality(data_intro, data_std);// 计算比值double avx_vs_normal = avx_time / normal_time;double intro_vs_normal = intro_time / normal_time;double std_vs_normal = std_time / normal_time;double avx_vs_std = avx_time / std_time;double intro_vs_std = intro_time / std_time;// 确定性能排名vector<pair<double, string>> times = {{normal_time, "普通"},{avx_time, "AVX"},{intro_time, "内省"},{std_time, "标准库"}};sort(times.begin(), times.end());string ranking;for (int j = 0; j < 4; j++) {if (j > 0) ranking += " > ";ranking += times[j].second;}cout << left << setw(8) << i + 1<< setw(15) << fixed << setprecision(2) << normal_time<< setw(15) << fixed << setprecision(2) << avx_time<< setw(15) << fixed << setprecision(2) << intro_time<< setw(15) << fixed << setprecision(2) << std_time<< setw(15) << fixed << setprecision(3) << avx_vs_normal<< setw(15) << fixed << setprecision(3) << intro_vs_normal<< setw(15) << fixed << setprecision(3) << std_vs_normal<< setw(15) << fixed << setprecision(3) << avx_vs_std<< setw(15) << fixed << setprecision(3) << intro_vs_std<< setw(20) << ranking << endl;}// 计算平均时间double normal_avg = normal_total_time / num_tests;double avx_avg = avx_total_time / num_tests;double intro_avg = intro_total_time / num_tests;double std_avg = std_total_time / num_tests;// 计算平均比值double avx_vs_normal_avg = avx_avg / normal_avg;double intro_vs_normal_avg = intro_avg / normal_avg;double std_vs_normal_avg = std_avg / normal_avg;double avx_vs_std_avg = avx_avg / std_avg;double intro_vs_std_avg = intro_avg / std_avg;// 确定平均性能排名vector<pair<double, string>> avg_times = {{normal_avg, "普通"},{avx_avg, "AVX"},{intro_avg, "内省"},{std_avg, "标准库"}};sort(avg_times.begin(), avg_times.end());string avg_ranking;for (int j = 0; j < 4; j++) {if (j > 0) avg_ranking += " > ";avg_ranking += avg_times[j].second;}// 找出最佳算法string best_algorithm = avg_times[0].second;string best_algorithm_note = "性能最佳算法: " + best_algorithm;cout << "------------------------------------------------------------------------------------------------------------------------------------------------------------------------" << endl;cout << left << setw(8) << "平均"<< setw(15) << fixed << setprecision(2) << normal_avg<< setw(15) << fixed << setprecision(2) << avx_avg<< setw(15) << fixed << setprecision(2) << intro_avg<< setw(15) << fixed << setprecision(2) << std_avg<< setw(15) << fixed << setprecision(3) << avx_vs_normal_avg<< setw(15) << fixed << setprecision(3) << intro_vs_normal_avg<< setw(15) << fixed << setprecision(3) << std_vs_normal_avg<< setw(15) << fixed << setprecision(3) << avx_vs_std_avg<< setw(15) << fixed << setprecision(3) << intro_vs_std_avg<< setw(20) << avg_ranking << endl;cout << "========================================================================================================================================================================" << endl;cout << best_algorithm_note << endl;cout << "========================================================================================================================================================================" << endl << endl;
}int main() {cout << "排序算法性能测试" << endl;cout << "==========================================" << endl << endl;// 测试不同数据量performance_test(100000);performance_test(500000);performance_test(1000000);performance_test(5000000);return 0;
}

最终优化建议:在实际工程中,建议创建动态阈值适配层,根据运行时数据特征自动选择最优策略

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

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

相关文章

Linux驱动开发重要操作汇总

本文主要记录imx6ull的linux驱动开发过程中常用的一些操作。 uboot编译 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- distclean make ARCHarm CROSS_COMPILEarm-linux-gnueabihf mx6ull_14x14_evk_emmc_defconfig make V1 ARCHarm CROSS_COMPILEarm-linux-gnueabihf- …

【Java后端】MySQL 常见 SQL 语句优化指南

在 MySQL 中&#xff0c;SQL 优化是性能调优的核心环节&#xff0c;尤其是在数据量大、并发高的情况下。这里整理一份 MySQL 常见 SQL 语句优化指南&#xff0c;从查询写法、索引使用到执行计划分析&#xff0c;涵盖实用技巧&#xff1a;1. 查询语句层面的优化 ✅ 避免 SELECT …

Golang 面试题「高级」

以下是 100 道 Golang 高级面试题及答案&#xff0c;聚焦语言底层实现、并发深度优化、性能调优、源码级理解等核心方向&#xff0c;适合资深开发者或架构师级别的面试场景&#xff1a; 一、GPM 调度模型与并发深度 问题&#xff1a;Goroutine 的栈空间初始大小是多少&#xff…

WebGIS视角:体感温度实证,哪座“火炉”火力全开?

目录 前言 一、火炉城市空间分布及特点 1、空间分布 2、气候特点 二、数据来源及技术实现 1、数据来源介绍 2、技术路线简介 三、WebGIS系统实现 1、后端设计与实现 2、前端程序实现 四、成果展示 1、整体展示 2、蒸烤模式城市 3、舒适城市 五、总结 前言 “火炉…

《数据结构入门:顺序表的结构设计与核心操作(C 语言版)》

目录 一. 线性表 二. 顺序表的概念与结构 2.1 核心概念 2.2 两种常见结构 静态顺序表 动态顺序表 2.3 核心区别对比 四. 顺序表的实现 4.1 顺序表的定义 4.2 顺序表初始化 4.3 动态顺序表容量检查与扩容 4.4 动态顺序表插入数据 4.4.1 头插 4.4.2 尾插 4.4.3 指…

[Maven 基础课程]Maven 是什么

Maven 的官方网站&#xff1a;https://maven.apache.org/ 来自 Maven 官网的对于 Maven 是什么的描述&#xff1a; Apache Maven is a build tool for Java projects. Using a project object model (POM), Maven manages a project’s compilation, testing, and documentat…

【MATLAB例程】三维组合导航,滤波使用EKF,带严格的惯导推算、雅克比求解函数,图像对比滤波前后的速度、位置、姿态

文章目录程序介绍系统建模滤波框架仿真设置性能对比代码优点运行结果MATLAB源代码程序介绍 本程序实现了 三维状态量的扩展卡尔曼滤波&#xff08;EKF&#xff09;组合导航仿真&#xff0c;采用严格的15维误差状态模型&#xff0c;状态向量包括&#xff1a; x[pxpypzvxvyvzϕθ…

港资企业在大陆,如何靠 SD-WAN 专线畅连香港?

在当前市场形势下&#xff0c;港资企业在大陆的业务布局不断拓展&#xff0c;企业间访问香港总部系统以及香港员工到内陆出差时访问相关系统&#xff0c;成为日常运营的高频需求。然而&#xff0c;网络问题却常常阻碍业务的顺畅开展&#xff0c;基于 SD-WAN 专线的到香港加速网…

并发编程——08 Semaphore源码分析

1 概述Semaphore 是基于 AQS CAS 实现的&#xff0c;可根据构造参数的布尔值&#xff0c;选择使用公平锁&#xff0c;还是非公平锁。Semaphore 默认使用非公平锁&#xff1b;2 构造函数 // AQS的实现 private final Sync sync;// 默认使用非公平锁 public Semaphore(int permi…

Java全栈开发面试实战:从基础到微服务的深度解析

Java全栈开发面试实战&#xff1a;从基础到微服务的深度解析 一、面试开场 面试官&#xff08;中年工程师&#xff0c;穿着休闲但专业&#xff09;&#xff1a;你好&#xff0c;我是李工&#xff0c;今天来聊一下你的技术背景。你之前在XX科技做全栈开发&#xff0c;对吧&#…

CVPR深度学习论文创新合集拆解:模型训练速度算提升

关注gongzhonghao【CVPR顶会精选】大语言模型扩散Transformer的深度融合&#xff0c;让文本到图像生成更精准、细节更丰富&#xff1b;同时&#xff0c;专家轨迹正则化深度强化学习在自动对焦中的稳定加速表现&#xff0c;也展示了深度学习与轨迹建模结合的潜力。这样的组合正在…

【智能体】零代码学习 Coze 智能体(2)创建智能体的完整步骤

欢迎关注【AGI使用教程】 专栏 【智能体】零代码学习 Coze 智能体&#xff08;1&#xff09; 【智能体】零代码学习 Coze 智能体&#xff08;2&#xff09; 【智能体】零代码学习 Coze 智能体&#xff08;1&#xff09;1、登录 Coze 平台2、创建智能体3、智能体编排页面4、编写…

WPF和WinFrom区别

WPF 总结Windows Presentation Foundation (WPF) 是微软开发的一个用于构建 Windows 桌面应用程序的用户界面框架。它基于 .NET Framework&#xff0c;提供丰富的图形、动画和数据绑定功能&#xff0c;帮助开发者创建现代化、高性能的应用程序。以下是其核心要点总结&#xff1…

数据库原理及应用_数据库基础_第3章数据库编程_常用系统函数

前言 "<数据库原理及应用>(MySQL版)".以下称为"本书"中3.1.2节内容 引入 数据库常用系统函数的分析.上一篇帖子分析了,数据库函数需要看看能否被C语言函数替代 1.字符串函数 1)计算字符串字符数的函数和字符串长度的函数 语法: CHAR_LENGTH(str)…

回归问题的损失函数

简单来说&#xff0c;​在回归问题中&#xff0c;最常用的损失函数是均方误差&#xff08;MSE, Mean Squared Error&#xff09;和平均绝对误差&#xff08;MAE, Mean Absolute Error&#xff09;​。它们衡量的都是模型预测值&#xff08;ŷ&#xff09;与真实值&#xff08;y…

吴恩达机器学习(四)

一、神经网络神经元模拟逻辑单元&#xff1a;神经网络简单模型&#xff1a;神经网络中的前向传播过程&#xff1a;依次计算激活项&#xff0c;从输入层到隐藏层再到输出层的过程。样例&#xff1a;多元分类&#xff1a;

【重学 MySQL】九十三、MySQL的字符集的修改与底层原理详解

【重学 MySQL】九十三、MySQL的字符集的修改与底层原理详解一、字符集修改方法1. **配置文件修改**2. **SQL命令修改**3. **数据迁移方案**二、底层原理与注意事项1. **字符集与排序规则**2. **存储与性能影响**3. **数据一致性风险**三、常见问题解决1. **乱码问题**2. **性能…

pdf 转图片工具实现

一、安装 sudo yum install poppler-utils pdftoppm -v pdftoppm -png -r 300 a.pdf /tmp/page 运行效果&#xff1a; PDF转图片工具 - 在线PDF转PNG/JPG/TIFF转换器 | 免费在线工具 后台实现&#xff1a; using System.Diagnostics; using System.IO.Compression;namespac…

Zynq开发实践(FPGA之输入、输出整合)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】fpga开发的时候习惯上先把功能拆分成若干个模块。针对这些模块&#xff0c;一个一、个实现好之后&#xff0c;再用wire连接即可。这一点有点像软件编…

【Linux基础】深入理解计算机启动原理:MBR主引导记录详解

目录 引言 1 硬盘分区初始化概述 1.1 为什么需要硬盘分区 1.2 硬盘分区格式的发展 1.3 分区初始化的基本流程 2 MBR详解 2.1 MBR的定义与位置 2.2 MBR的结构详解 2.3 分区表结构详解 2.4 MBR的工作原理 2.5 MBR的引导程序 3 MBR的局限性 3.1 硬盘容量限制 3.2 分…