unlikely和likely

本文解释了likely()和unlikely()宏如何用于提高CPU分支预测的准确性,从而提升代码执行效率。这些宏告诉编译器哪些条件分支更可能被执行,进而允许编译器优化指令流程。
    主要是跟处理器有关,现在处理器都是流水线的,有些里面有多个逻辑运算单元,系统可以提前取多条指令进行并行处理,但遇到跳转时,则需要重新取指令,这相对于不用重新去指令就降低了速度。所以对unlikely的宏,系统运行时,将减少跳转,重新取指。

与assert()是不一样的,assert()是对一个值进行判断,如指针是否为NULL,如果为NULL,则程序直接exit。跟unlikely是不用级别上的东西,功能也不一样,

    增加条件分支预测的准确性,cpu会提前装载后面的指令,遇到条件转移指令时会提前预测并装载某个分支的指令。unlikely表示你可以确认该条件是极少发生的,相反likely表示该条件多数情况下会发生。编译器会产生相应的代码来优化cpu执行效率。

 

在 2.6 内核中,随处可以见到 likely() 和 unlikely() 的身影,那么为什么要用它们?它们之间有什么区别?

  首先要明确:

  if(likely(value)) 等价于 if(value)

  if(unlikely(value)) 也等价于 if(value)

  也就是说 likely() 和 unlikely() 从阅读和理解代码的角度来看,是一样的!!!

  这两个宏在内核中定义如下:

  #define likely(x) __builtin_expect((x),1)

  #define unlikely(x) __builtin_expect((x),0)

  __builtin_expect() 是 GCC (version >= 2.96)提供给程序员使用的,目的是将“分支转移”的信息提供给编译器,这样编译器可以对代码进行优化,以减少指令跳转带来的性能下降。

  __builtin_expect((x),1) 表示 x 的值为真的可能性更大;

  __builtin_expect((x),0) 表示 x 的值为假的可能性更大。

  也就是说,使用 likely() ,执行 if 后面的语句 的机会更大,使用unlikely(),执行else 后面的语句的机会更大。

在 C/C++ 编程中,`likely` `unlikely` 是用于**优化分支预测**的宏,它们并不是语言内置关键字,而是通过编译器内置函数(如 GCC 或 Clang 的 `__builtin_expect`)实现的。它们帮助编译器生成更高效的机器码,特别是在条件判断中指明某个分支是“大概率发生”还是“小概率发生”。 --- ### ✅ `likely` `unlikely` 的等价实现 ```c #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) ``` #### 解释: - `__builtin_expect(expr, expected_value)`: - 告诉编译器 `expr` 的值**预期为** `expected_value`。 - 这只是一个提示,不影响逻辑,但会影响生成的汇编代码中分支的布局(热路径优化)。 - `!!(x)`: - 将任意表达式 `x` 转换为布尔值(0 或 1),确保传给 `__builtin_expect` 的是明确的布尔上下文。 - `likely(x)`:表示 `x` 很可能为真(即期望为 1) - `unlikely(x)`:表示 `x` 很不可能为真(即期望为 0) --- ### 📌 使用示例(C语言) ```c #include <stdio.h> #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) void test_function(int flag) { if (likely(flag == 1)) { printf("Flag is 1 (common case)\n"); } else if (unlikely(flag == 0)) { printf("Flag is 0 (rare case)\n"); } } ``` #### 汇编层面的影响(以 x86 为例): - `likely` 分支会被编译器放在“直通路径”(fall-through),减少跳转开销。 - `unlikely` 分支会生成跳转指令,避免污染指令缓存。 --- ### 💡 等价替代方式 虽然没有标准库直接提供 `likely/unlikely`,但在不同环境中有等价或近似机制: #### 1. **C++20 及以后:`[[likely]]` `[[unlikely]]` 属性(官方标准)** ```cpp void func(int flag) { if (flag == 1) [[likely]] { printf("Common case\n"); } else [[unlikely]] { printf("Rare case\n"); } } ``` > 这是现代 C++ 的标准写法,语义清晰且由编译器优化支持。 #### 2. **无提示(普通写法)——功能等价但无性能提示** ```c if (flag == 1) { // ... } else { // ... } ``` > 功能上完全一样,但编译器无法做最佳分支预测优化。 --- ### 🔍 实际应用场景 - 内核开发(Linux Kernel 大量使用 `likely/unlikely`) - 高性能服务中的错误处理(如 `if (unlikely(err)) handle_error();`) - 热路径优化 --- ### ❗注意事项 - 这些宏仅在 GCC/Clang 等支持 `__builtin_expect` 的编译器上有意义。 - 在 MSVC 中不支持 `__builtin_expect`,可使用条件编译规避: ```c #ifdef __GNUC__ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #else #define likely(x) (x) #define unlikely(x) (x) #endif ``` --- ### 总结 | 写法 | 是否等价 | 说明 | |------|----------|------| | `likely(x)` | ✅ 功能+优化等价 | 使用 `__builtin_expect(x, 1)` 提示编译器 | | `unlikely(x)` | ✅ 功能+优化等价 | 使用 `__builtin_expect(x, 0)` | | C++20 `[[likely]]` / `[[unlikely]]` | ✅ 语义等价且更现代 | 推荐新项目使用 | | 普通 `if` | ✅ 功能等价 ❌ 无优化提示 | 缺少编译器优化线索 | ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值