Linux中的likely()与unlikely()

likely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢?
首先明确:
 if (likely(value))等价于if (value)
 if (unlikely(value))等价于if (value)


也就是说likely()和unlikely()从阅读和理解的角度是一样的。

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

<linux/compiler>

#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
这里的__built_expect()函数是gcc(version >= 2.96)的内建函数,提供给程序员使用的,目的是将"分支转移"的信息提供给编译器,这样编译器对代码进行优化,以减少指令跳转带来的性能下降。
__buildin_expect((x), 1)表示x的值为真的可能性更大.
__buildin_expect((x), 0)表示x的值为假的可能性更大.
也就是说,使用likely(),执行if后面的语句的机会更大,使用unlikely(),执行else后面的语句机会更大一些。通过这种方式,编译器在编译过程中,会将可能性更大的代

码紧跟着后面的代码,从而减少指令跳转带来的性能上的下降。

比如 :
if (likely(a>b)) {
  fun1();

}
if (unlikely(a<b)) {
 fun2();
}

  这里就是程序员可以确定 a>b 在程序执行流程中出现的可能相比较大,因此运用了likely()告诉编译器将fun1()函数的二进制代码紧跟在前面程序的后面,这样就

cache在预取数据时就可以将fun1()函数的二进制代码拿到cache中。这样,也就添加了cache的命中率。

  同样的,unlikely()的作用就是告诉编译器,a<b 的可能性很小所以这里在编译时,将fun2()的二进制代码尽量不要和前边的编译在一块。

  咱们不用对likely和unlikely感到迷惑,须要知晓的就是 if(likely(a>b)) 和 if(a>b)在功能上是等价的,同样 if(unlikely(a<b)) 和 if(a<b) 的功能也是一样的。不一样的只是他们声称的二进制代码有所不一样,这一点咱们也可以从他们的汇编代码中看到。

  比如下面的代码:

  #include <stdio.h>

  #define unlikely(x) __builtin_exp ect(!!(x), 0)

  #define likely(x) __builtin_exp ect(!!(x), 1)

int main()

  {

  int a=2,b=4;

  if(unlikely(a<b)) {

  printf("in the unlikely,is not your exp ecting!\n");

  } else {

  printf("in the unlikely, is your exp ecting\n");

  }

  if(likely(a<b)) {

  printf("in the likely, is your exp ecting\n");

  }

  return 0;

  }

  执行结果:

  in the unlikely,is not your exp ecting!

  in the likely, is your exp ecting

  总之,likely和unlikely的功能就是添加 cache的命中率,提高系统执行速度。


<think>好的,我现在要解决用户关于likelyunlikely在编程中的含义及用法的问题。首先,我需要回忆自己之前学过的相关知识,并结合提供的引用内容来整理答案。 用户提到的这几个引用中,引用[1]提到了`__builtin_expect(EXP, N)`的用法,说明likelyunlikely是基于这个内置函数的宏,用来告诉编译器条件判断的结果更可能是什么。引用[2]指出这是Linux内核中的优化手段,用于条件分支的性能优化。引用[3]则具体解释了宏的用法,分别标记条件为真或假的可能性,帮助编译器优化代码布局。 首先,我需要解释likelyunlikely的基本含义,它们的作用是给编译器提供分支预测的信息,从而生成更高效的机器码。比如,使用likely告诉编译器这个条件很可能为真,那么编译器可能会将更可能执行的代码放在前面,减少跳转带来的性能损耗。 接下来,应该详细说明它们的实现方式,即通过GCC的`__builtin_expect`函数,将条件的期望值传递给编译器。例如,`likely(x)`实际上就是`__builtin_expect(!!(x), 1)`,而unlikely则是期望值为0。 然后,需要举例说明在代码中如何使用这两个宏,比如在条件判断语句中包裹条件表达式,帮助编译器优化分支预测。例如,在错误处理或者罕见情况的条件判断时使用unlikely,而在正常流程的条件判断时使用likely。 同时,应该提到使用这两个宏的注意事项,比如不要滥用,只在确实有明确倾向性的分支中使用,否则可能导致性能下降。另外,需要指出它们主要适用于GCC编译器,其他编译器可能有不同的实现方式。 最后,根据用户提供的示例中的结构,生成相关问题,比如优化原理、适用场景、其他优化方法的对比等。 检查是否有遗漏的部分,比如是否涵盖了定义、实现原理、代码示例、注意事项,以及相关问题是否合理。确保引用的内容被正确标注,比如引用[^2]对应Linux内核的应用,引用[^3]对应具体用法示例。 现在需要将这些内容组织成结构清晰的回答,符合用户要求的格式,使用中文,正确使用LaTeX格式,比如内联公式用$符号,独立公式用$$。不过当前问题可能不涉及数学公式,所以可能不需要使用数学表达式,但需要保持结构清晰,分点说明。 总结,回答的结构应该是: 1. 定义和作用 2. 实现原理(基于GCC内置函数) 3. 具体用法示例 4. 使用注意事项 5. 相关问题 确保每个部分都参考了提供的引用内容,并正确标注引用标识。同时,生成的代码示例需要用反引号包裹,正确显示语法高亮。</think>### likelyunlikely的含义及用法 #### 1. 定义作用 `likely`和`unlikely`是编程中用于优化条件分支性能的宏。它们通过向编译器提供分支条件的概率信息,帮助编译器生成更高效的机器码。例如: - `likely(condition)`:表示`condition`为真的概率很大。 - `unlikely(condition)`:表示`condition`为假的概率很大。 #### 2. 实现原理 这两个宏基于GCC的`__builtin_expect`内置函数实现,语法为: ```c #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) ``` - `__builtin_expect(EXP, N)`:提示编译器`EXP == N`的概率很高[^1]。 - `!!(x)`:将任意表达式转换为布尔值(0或1),确保逻辑一致性。 #### 3. 代码示例 **场景1**:处理常见路径(使用`likely`) ```c if (likely(data_valid)) { // 数据有效时的高频操作 } else { // 错误处理的低频路径 } ``` **场景2**:处理罕见错误(使用`unlikely`) ```c if (unlikely(file_open_failed)) { // 文件打开失败的异常处理 } else { // 正常文件操作 } ``` #### 4. 注意事项 1. **适用场景**:明确分支概率时使用(如错误处理、核心循环)。 2. **编译器依赖**:主要针对GCC/Clang,其他编译器需适配(如MSVC的`__assume`)。 3. **避免滥用**:错误预测可能降低CPU流水线效率。 4. **内核应用**:广泛用于Linux内核(如网络栈、文件系统)[^2]。 #### 5. 性能优化机制 编译器会根据提示调整: - **代码布局**:高频路径紧邻无跳转指令,减少流水线冲刷。 - **分支预测**:生成`cmov`等无分支指令(概率极高时)。 - 汇编对比示例: ```asm ; 使用likely时 test %eax, %eax jne .Lhigh_prob_path ; 预测不跳转 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值