读书人

转 Linux上pipe使用注意事项

发布时间: 2012-09-22 21:54:54 作者: rapoo

转 Linux下pipe使用注意事项
转http://blog.yufeng.info/archives/1485

Linux下pipe使用注意事项作者:Yu Feng原创文章,转载请注明: 转载自Erlang非业余研究本文链接地址: Linux下pipe使用注意事项Linux下的pipe使用非常广泛, shell本身就大量用pipe来粘合生产者和消费者的. 我们的服务器程序通常会用pipe来做线程间的ipc通讯. 由于unix下的任何东西都是文件,只要是文件,在读取的时候,,就会设置last access time, 所以pipe也不例外., 但是这个时间对我们没有意义 如果pipe使用的非常频繁的时候会碰到由于设置访问时间导致的性能问题. 这个开销远比pipe读写的本身开销大. 相比文件读写的开销, atime微不足道,但是对pipe来讲就不同了.这个事情是上次和多隆同学在把玩他的网络框架的时候,无意发现的.我们来分析下pipe的这部分代码://pipe.c:L349static ssize_tpipe_read(struct kiocb *iocb, const struct iovec *_iov,               unsigned long nr_segs, loff_t pos){...   if (ret > 0)        file_accessed(filp);    return ret;}我们可以看到在pipe读的时候要设置 file_accessed时间的,接着://fs.h:L1761extern void touch_atime(struct vfsmount *mnt, struct dentry *dentry);static inline void file_accessed(struct file *file){        if (!(file->f_flags & O_NOATIME))                touch_atime(file->f_path.mnt, file->f_path.dentry);}如果文件没设置 O_NOATIME就真正动手设置atime,接着://inode.c:L1493void touch_atime(struct vfsmount *mnt, struct dentry *dentry){        struct inode *inode = dentry->d_inode;        struct timespec now;        if (inode->i_flags & S_NOATIME)                return;        if (IS_NOATIME(inode))                return;        if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))                return;        if (mnt->mnt_flags & MNT_NOATIME)                return;        if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))                return;        now = current_fs_time(inode->i_sb);        if (!relatime_need_update(mnt, inode, now))                return;        if (timespec_equal(&inode->i_atime, &now))                return;        if (mnt_want_write(mnt))                return;        inode->i_atime = now;        mark_inode_dirty_sync(inode);        mnt_drop_write(mnt);}我们可以看出上面的流程还是比较复杂的,开销也很大.我们来演示下:$ cat > pipe_test.c#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <assert.h>#include <pthread.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#include <linux/unistd.h>static int fds[2];static pthread_t rp;static void *rp_entry(void *arg) {  char c[1];  while (1 == read(fds[0], c, 1)) {    if (*c == 'Q') break;  }  fprintf(stderr, "pipe read ok\n");  return NULL;}int main(int argc, char *argv[]) {  long i, n;  int rc;  if (argc < 2) {    fprintf(stderr, "usage: pipe_test NNNNNN\n");    return -1;  }  n = atol(argv[1]);  pipe(fds);  //fcntl(fds[0], F_SETFL, O_NOATIME);  pthread_create(&rp, NULL, rp_entry, NULL);  fprintf(stderr, "pipe write %ld...", n);  for (i = 0; i < n; i++) {    write(fds[1], "A", 1);  }  write(fds[1], "Q", 1);  fprintf(stderr, "ok\n");  pthread_join(rp, NULL);  close(fds[0]);  close(fds[1]);  return 0;}CTRL+D$ gcc -D_GNU_SOURCE pipe_test.c -lpthread$ sudo opcontrol --setup --vmlinux=/usr/lib/debug/lib/modules/2.6.18-164.el5/vmlinux$ sudo opcontrol --init && sudo opcontrol --reset && sudo opcontrol --start$ ./a.out 10000000pipe write 10000000...okpipe read ok$ sudo opcontrol --shutdown$ opreport -l|lesssamples  %        app name                 symbol name378654   92.7742  vmlinux                  .text.acpi_processor_idle12978     3.1797  vmlinux                  current_fs_time2530      0.6199  vmlinux                  thread_return2345      0.5745  vmlinux                  touch_atime2253      0.5520  vmlinux                  .text.acpi_safe_halt1597      0.3913  vmlinux                  timespec_trunc1368      0.3352  vmlinux                  file_update_time1253      0.3070  vmlinux                  __mark_inode_dirty901       0.2208  vmlinux                  pipe_writev768       0.1882  vmlinux                  __mutex_lock_slowpath763       0.1869  vmlinux                  try_to_wake_up270       0.0662  vmlinux                  copy_user_generic_unrolled254       0.0622  vmlinux                  acpi_set_register254       0.0622  vmlinux                  system_call233       0.0571  vmlinux                  pipe_readv188       0.0461  vmlinux                  dnotify_parent167       0.0409  vmlinux                  mutex_unlock...我们可以看到touch_atime的开销很大,远比pipe的读写大.这次把这行注释去掉: fcntl(fds[0], F_SETFL, O_NOATIME); 指示pipe在读的时候不更新atime,看下效果:$ opreport -l|lesssamples  %        app name                 symbol name599018   95.2466  vmlinux                  .text.acpi_processor_idle4140      0.6583  vmlinux                  .text.acpi_safe_halt3281      0.5217  vmlinux                  thread_return2812      0.4471  vmlinux                  current_fs_time2615      0.4158  vmlinux                  file_update_time1790      0.2846  vmlinux                  __mutex_lock_slowpath1657      0.2635  vmlinux                  timespec_trunc1341      0.2132  vmlinux                  try_to_wake_up1281      0.2037  vmlinux                  mutex_unlock1080      0.1717  vmlinux                  mutex_lock1001      0.1592  vmlinux                  pipe_readv925       0.1471  vmlinux                  pipe_writev这下看不到touch_atime了,开销省了,对于高性能服务器是很重要的.小结: 细节很重要,记得开文件open的时候设置O_NOATIME或者用fcntl搞定它.祝玩得开心!

读书人网 >UNIXLINUX

热点推荐