当前位置: 首页 > 科技观察

Linux大文件重定向与管道效率对比

时间:2023-03-12 18:36:56 科技观察

#命令1,管道importshell>cathuge_dump.sql|mysql-uroot;#命令2,redirectimportshell>mysql-uroot0);return0;}$gcc-ob.outb.c$ls|./b.out下面我们写一个systemtap脚本,方便观察程序的行为。$cattest.stpfunctionshould_log(){return(execname()=="cat"||execname()="b.out"||execname()=="bash");}probesyscall.open,syscall.close,syscall.read,syscall.write,syscall.pipe,syscall.fork,syscall.execve,syscall.dup,syscall.wait4{if(!should_log())next;printf("%s->%s\n",thread_indent(0),probefunc());}probekernel.function("pipe_read"),kernel.function("pipe_readv"),kernel.function("pipe_write"),kernel.function("pipe_writev"){if(!should_log())next;printf("%s->%s:fileino%d\n",thread_indent(0),probefunc(),__file_ino($filp));}probebegin{println(":~")}这个脚本重点观察几个系统调用的顺序和管道的读写,然后准备了一个419M的huge_dump.sql大文件,在我们几十G内存的机器上很容易放到内存中:$sudoddif=/dev/urandomof=huge_dump.sqlbs=4096count=102400102400+0recordsin102400+0recordsout419430400bytes(419MB)copied,63.9886seconds,6.6MB/s因为这个文件是写在bufferio里面的,里面的内容都是cached在pagecahce内存中,不会涉及磁盘。好了,场景完成,我们来对比下两种情况的速度,第一种管道:#第一种管道方法$time(cathuge_dump.sql|./b.out)real0m0.596suser0m0.001ssys0m0.919s#第二种重定向method$time(./b.outhuge_dump.sql$sudostaptest.stp:~0bash(26570):->sys_read0bash(26570):->sys_read0bash(26570):->sys_write0bash(26570):->sys_read0bash(26570):->sys_write0bash(26570):->sys_close0bash(26570):->sys_close0bash(26570)):->sys_pipe0bash(26570):->sys_pipe0bash(26570):->do_fork0bash(26570):->sys_close0bash(26570):->sys_close0bash(26570):->do_fork0bash(13775):->sys_close0bash(13775):->sys_read0bash(13775):->pipe_read:fileino209069110bash(13775):->pipe_readv:fileino209069110bash(13776):->sys_close0bash(13776):->sys_close0bash(13776):->sys_close0bash(13776):->:265570bash(->sys_close0bash(26570):->sys_close0bash(26570):->sys_close0bash(13775):->sys_close0bash(26570):->sys_wait40bash(13775):->sys_close0bash(13775):->sys_close0b.out(13776):->sys_close0b.out(13776):->sys_close0bash(13775):->do_execve0b.out(13776):->sys_open0b.out(13776):->sys_close0b.out(13776):->sys_open0b.out(13776):->sys_read0b.out(13776):->sys_close0cat(13775):->sys_close0cat(13775):->sys_close0b.out(13776):->sys_read0b.out(13776):->pipe_read:fileino209069100b.out(13776):->pipe_readv:fileino209069100cat(13775):->sys_open0cat(13775):->sys_close0cat(13775)):->sys_open0cat(13775):->sys_read0cat(13775):->sys_close0cat(13775):->sys_open0cat(13775):->sys_close0cat(13775):->sys_open0cat(13775):->sys_read0cat(13775):->sys_write0cat(13775):->pipe_write:fileino209069100cat(13775):->pipe_writev:fileino209069100cat(13775):->sys_read0b.out(13776):->sys_read0b.out(13776):->pipe_read:fileino209069输出(13776):->pipe_readv:fileino209069100cat(13775):->sys_close0cat(13775):->sys_close0bash(26570):->sys_wait40bash(26570):->sys_close0bash(26570):->sys_wait40bash(26570):->sys_writesap正在收集数据,我们在另一个窗口中运行管道:$cahuge_dump.sql|./b.out从systemtap日志我们可以看到:bashfork了两个进程,然后execve分别运行了cat和b.out进程,这两个进程通过管道进行通信。cat从huge_dump.sql中读取数据,写入管道,然后从管道中读取b.out进行处理。然后看命令2的重定向:$./b.outsys_read0bash(26570):->sys_read0bash(26570):->sys_write0bash(26570):->sys_read0bash(26570):->sys_write0bash(26570):->sys_close0bash(26570):->sys_pipe0bash(26570):->do_fork0bash(28926):->sys_close0bash(28926):->sys_read0bash(28926):->pipe_read:fileino209209020bash(28926):->pipe_readv:fileino209209020bash(26570):->sys_close0bash(26570):->sys_close0bash(26570):->sys_wait40bash(sys28926):->sys_close0bash(28926):->sys_close0bash(28926):->6:-_bash(s)28926):->do_execve0b.out(28926):->sys_close0b.out(28926):->sys_close0b.out(28926):->sys_open0b.out(28926):->sys_close0b.out(28926):->sys_open0b.out(28926):->sys_read0b.out(28926):->sys_close0b.out(28926):->sys_read0b.out(28926):->sys_read0bash(26570):->sys_wait40bash(26570):->sys_write0bash(26570):->sys_readbash分叉了一个进程并打开了数据文件。然后得到文件句柄handle0,这个进程execvesb.out。然后b.out直接读取数据。现在很清楚为什么两个场景的速度相差3倍了:Command1,流水线方式:读两次,写一次,加上一个进程上下文切换。命令2,重定向方式:只读一次。结论:Linux下大文件重定向效率更高。