查看原文
其他

说说Linux系统调用那些事儿

混说Linux 2022-11-19
点击上方蓝色“混说Linux”,选择“设为星标
第一时间看干货文章



 1

开门见山的说吧,使用系统调用(例如open()read()write()等函数)会影响系统的性能。

与函数调用相比,系统调用的开销要大一些,因为在执行系统调用时,Linux必须从运行用户代码切换到执行内核代码,然后再返回用户代码。


减少这种开销的一个好办法是,在程序中尽量减少系统调用的次数,并且让每次系统调用完成尽可能多的工作。

下面我们通过几个简单的栗子来说明一下为什么会这样。


 

.
频繁使用系统调用的例子


下面是一个关于文件复制的程序,看起来非常的简单,我们首先使用系统调用来完成文件复制的操作,为了体现频繁的系统调用,程序中将每次读写的数据块大小设为1byte,被复制的文件大小为1M。

/*copy_system1.c*/
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

int main()
{
    char c;
    int in, out;

    in = open("file.in", O_RDONLY);
    out = open("file.out", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    while (read(in, &c, 1) == 1)
    {
        write(out, &c, 1);
    }
    return 0;
}


通过这种方式运行这个程序:

TIMEFORMAT"" time ./copy_system


你会得到这样的输出结果:

4.33user 6.08system 0:10.42elapsed 99%CPU (0avgtext+0avgdata 412maxresident)k
0inputs+2048outputs (0major+145minor)pagefaults 0swaps


从这个结果中,我们不难发现程序运行了10s左右,而且CPU占有率高达99%,足见其效率低下。


NOTE:这个程序在运行之前你要准备一个大约1M的文件file.in,你可以用这个程序来生成你想要的这个文件。


 

.
减少系统调用的次数的例子

 

下面我们改变数据块的大小,再来测试一下,这样做可以减少系统调用的次数,下面是这个程序:

/*copy_system2.c*/
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

int main()
{
    char block[1024];
    int in, out;
    int nread;

    in = open("file.in", O_RDONLY);
    out = open("file.out", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
    while (nread = read(in, block, 1024) > 0)
    {
        write(out, block, nread);
    }
    return 0;
}


同样使用下面的命令来运行:

TIMEFORMAT="" time ./copy_system2


输出结果:

0.01user 0.01system 0:00.02elapsed 92%CPU (0avgtext+0avgdata 408maxresident)k
0inputs+8outputs (0major+145minor)pagefaults 0swaps


结果很明显,这次执行只花费了0.02s,而且CPU占有率也降低到了92%。现在你看到了频繁系统调用的后果了吧。


 

.
不使用系统调用的例子

 

为了体现不使用系统调用的优势,我们再来写一个不使用系统调用的程序:

/*copy_system3.c*/
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int c;
    FILE *in, *out;

    in = fopen("file.in""r");
    out = fopen("file.out""w");

    while ((c = fgetc(in)) != EOF)
    {
        fputc(c, out);
    }
    return 0;
}


我们依然使用这个命令进行测试:

TIMEFORMAT="" time ./copy_system3


输出结果:

0.05user 0.01system 0:00.12elapsed 55%CPU (0avgtext+0avgdata 500maxresident)k
4128inputs+4096outputs (0major+167minor)pagefaults 0swaps


现在结果很明显,这个程序只花费了0.12s,而且CPU占有率仅为55%,说明不使用系统调用的程序运行起来效率明显高于使用系统调用的程序。



NOTE:这三个程序都是对大小为1M的文件进行复制。


通过上面这个表格,我们很容易得出这样的结论:

    • 系统调用会导致程序效率低下(程序1与程序3做对比) 

    • 频繁系统调用更会导致程序效率低下(程序1与程序2做对比) 


由此,我们可以得出提高程序效率的方法:

    • 尽量避免频繁使用系统调用; 

    • 如果不可避免的使用了系统调用,那么就充分利用这次系统调用,让它完成尽可能多的工作。 


参考:

Neil Matthew Richard Stones. Linux 程序设计(第四版). 人民邮电出版社

https://www.jianshu.com/p/2c60d669c9fb





关注微信公众号『混说Linux』,后台点击 关于混说 即可添加作者微信。

往期推荐

一文详解 | Linux find 命令

深入理解 Linux CPU的上下文切换

ARM Cortex-M内核复位启动过程分析

还不知道UART、I2C、SPI协议什么时候用?一文带你彻底搞懂


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存