1、简介

我们写一个测试程序,来测试下我们的电脑一秒钟可以打印出多少数字。思路很简单,我们只需要利用alarm函数定时1s。然后在while(1)中不断打印变量值就好。

2、代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>


int main()
{   
    alarm(1); //定时1s
    int i = 0;
    while(1)
    {
        printf("%d\n",i++);
    }
    return 0;
}

这个例子很简单,但是也有很多细节值得我们关注。

3、损耗时间

我们不妨用time来查看下该程序的执行时间:
alt
我们可以发现,这段程序的实际用时为1.003s。但是用户区+内核区的时间为0.061+0.448=0.509s。实际的损耗时间为0.494s。
那么损耗时间究竟损耗在哪儿了呢?其实是损耗在内核区与用户区的频繁切换上了。

程序实际执行时间 = 系统时间 + 用户时间 + 损耗时间

4、printf函数

要想搞明白其时间损耗的本质,我们首先要弄清楚这个printf函数。关于printf函数,我们要知道:

  • 调用printf函数是会引起用户区到内核区的切换的;————>因为printf函数是库函数,而且屏幕其实也是文件(linux下一切皆文件),所以printf把数据打印在屏幕上是写文件的过程,底层会调用write函数,每一次printf,都会从用户空间到内核空间的一个切换(或者是用户态到内核态的一个切换),这个是有开销的。
  • printf()会把数据先存入缓冲区,然后再打印到屏幕上;

缓冲区什么时候会刷新呢?
(1)缓冲区满
(2)程序结束
(3)强制刷新缓冲区,方法有:\n fflush(stdout);

所以上述程序之所以损耗时间那么久,原因我们就知道了。由于每次打印一个数字都调用\n刷新缓冲区,所以每次打印都会引起用户区到内核区的切换,频繁的切换损耗了程序大量的时间。

5、优化

程序运行时间的瓶颈在于IO,所以我们首选优化IO来优化我们的程序,我们可以不刷新缓冲区,等到缓冲区满再写,所以我们可以用文件重定向,由于文件操作是带缓冲的,所以涉及到用户区到内核区的切换频率大大减少。从而使损耗降低。