Linux下pipe使用注意事项

时间:2022-11-13 00:05:45

转自:http://blog.yufeng.info/archives/1485

Linux下的pipe使用非常广泛, shell本身就大量用pipe来粘合生产者和消费者的. 我们的服务器程序通常会用pipe来做线程间的ipc通讯. 由于unix下的任何东西都是文件,只要是文件,在读取的时候,,就会设置last access time, 所以pipe也不例外., 但是这个时间对我们没有意义 如果pipe使用的非常频繁的时候会碰到由于设置访问时间导致的性能问题. 这个开销远比pipe读写的本身开销大. 相比文件读写的开销, atime微不足道,但是对pipe来讲就不同了.
这个事情是上次和多隆同学在把玩他的网络框架的时候,无意发现的.

我们来分析下pipe的这部分代码:

//pipe.c:L349
static ssize_t
pipe_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:L1761
extern 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:L1493
void 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 10000000
pipe write 10000000...ok
pipe read ok
sudo opcontrol --shutdown
$ opreport -l|less            
samples  %        app name                 symbol name
378654   92.7742  vmlinux                  .text.acpi_processor_idle
12978     3.1797  vmlinux                  current_fs_time
2530      0.6199  vmlinux                  thread_return
2345      0.5745  vmlinux                  touch_atime
2253      0.5520  vmlinux                  .text.acpi_safe_halt
1597      0.3913  vmlinux                  timespec_trunc
1368      0.3352  vmlinux                  file_update_time
1253      0.3070  vmlinux                  __mark_inode_dirty
901       0.2208  vmlinux                  pipe_writev
768       0.1882  vmlinux                  __mutex_lock_slowpath
763       0.1869  vmlinux                  try_to_wake_up
270       0.0662  vmlinux                  copy_user_generic_unrolled
254       0.0622  vmlinux                  acpi_set_register
254       0.0622  vmlinux                  system_call
233       0.0571  vmlinux                  pipe_readv
188       0.0461  vmlinux                  dnotify_parent
167       0.0409  vmlinux                  mutex_unlock
...

我们可以看到touch_atime的开销很大,远比pipe的读写大.
这次把这行注释去掉: fcntl(fds[0], F_SETFL, O_NOATIME); 指示pipe在读的时候不更新atime,看下效果:

$ opreport -l|less
samples  %        app name                 symbol name
599018   95.2466  vmlinux                  .text.acpi_processor_idle
4140      0.6583  vmlinux                  .text.acpi_safe_halt
3281      0.5217  vmlinux                  thread_return
2812      0.4471  vmlinux                  current_fs_time
2615      0.4158  vmlinux                  file_update_time
1790      0.2846  vmlinux                  __mutex_lock_slowpath
1657      0.2635  vmlinux                  timespec_trunc
1341      0.2132  vmlinux                  try_to_wake_up
1281      0.2037  vmlinux                  mutex_unlock
1080      0.1717  vmlinux                  mutex_lock
1001      0.1592  vmlinux                  pipe_readv
925       0.1471  vmlinux                  pipe_writev

这下看不到touch_atime了,开销省了,对于高性能服务器是很重要的.
小结: 细节很重要,记得开文件open的时候设置O_NOATIME或者用fcntl搞定它.
祝玩得开心!

Post Footer automatically generated by wp-posturl plugin for wordpress.

Linux下pipe使用注意事项的更多相关文章

  1. ecmall在linux下的安装注意事项&lpar;转&rpar;

    今天跟ecshop客服胡娇沟通后知道ecmall基本配置是[LAMP] linux+apache+mysql+php,然后自己开始在linux下安装ecmall并做迁移,整理了一下中间碰到的问题.1. ...

  2. ecmall在linux下的安装注意事项&lpar;转&rpar; ----ecmall系统迁移

    linux+apache+mysql+php,然后自己开始在linux下安装ecmall并做迁移,整理了一下中间碰到的问题.1.系统选择的环境是centos6.3,安装不做介绍. 2.安装 MySQL ...

  3. anaconda在linux下的安装注意事项

    不应该做什么 官网原文: Installation Instructions Linux Install These instructions explain how to install Anaco ...

  4. linux 下SPI通信注意事项(待续)

    一.2台Linux设备之间使用SPI通信 1.标准Linux只支持Master 模式.但是可以在驱动中修改为Slave模式: 2.硬件SPI可能支持Slave模式,也可能不支持.这个要提前确认好: 3 ...

  5. 在linux下用tomcat部署java web项目的过程与注意事项

    在linux下用tomcat部署java web项目的过程与注意事项 一.安装JDK 到http://www.oracle.com/technetwork/java/javase/downloads/ ...

  6. linux 下 tomcat 运行报错 Broken pipe

    linux 下 tomcat 运行报错 Broken pipe 感谢:http://hi.baidu.com/liupenglover/blog/item/4048c23ff19f1cd67d1e71 ...

  7. linux下高并发网络应用注意事项

    本文转自:http://www.blogjava.net/bacoo/archive/2012/06/11/380500.html linux下高并发网络应用注意事项 vi /etc/sysctl.c ...

  8. 在linux下用tomcat部署java web项目的过程与注意事项(转)

    在linux下用tomcat部署java web项目的过程与注意事项一.安装JDK到http://www.oracle.com/technetwork/java/javase/downloads/in ...

  9. linux下php中文UTF-8转换Unicode方法和注意事项

    先说下遇到问题:1.php没有内置unicode_ecode函数可以直接使用 2.网上很多资料都是用$str = iconv($encoding, 'UCS-2', $str); window下转换出 ...

随机推荐

  1. java timer 执行任务

    1. 建立timer import java.util.Timer; import java.util.TimerTask; public class Start { public class Sta ...

  2. Kernel Methods &lpar;6&rpar; The Representer Theorem

    The Representer Theorem, 表示定理. 给定: 非空样本空间: \(\chi\) \(m\)个样本:\(\{(x_1, y_1), \dots, (x_m, y_m)\}, x_ ...

  3. 关闭和开启oracle

    1.使用sqlplus 启动和关闭数据库. 答:使用sqlplus以sysdba的身份登录数据库 因为我的数据库是启动状态,所以我就先演示数据库的关闭 数据库的关闭使用语句shutdown immed ...

  4. Android 学习笔记之数据存储SharePreferenced&plus;File

    学习内容: Android的数据存储.... 1.使用SharedPreferences来保存和读取数据... 2.使用File中的I/O来完成对数据的存储和读取...   一个应用程序,经常需要与用 ...

  5. ArcEngine10:ArcGIS version not specified&period; You must call RuntimeManager&period;Bind before creating any ArcGIS components&period;

    在Program.cs中添加ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDesktop);如下 static voi ...

  6. How to upload a file in MVC4

    Uploading a file in Asp.Net MVC application is very easy. The posted file is automatically available ...

  7. Mahout决策森林

    Mahout决策森林算法 一.决策树 决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法 ...

  8. shiro &plus; jwt 实现 请求头中的 rememberMe 时间限制功能

    前言: 上一篇提出, 通过修改 rememberMe 的编码来实现 rememberMe的功能的设想, 事后我去尝试实现了一番, 发现太麻烦, 还是不要那么做吧. 程序还是要越简单越好. 那功能总是要 ...

  9. Python标准数据类型的二次加工

    基于类继承的原理实现: class Li(list): #继承标准数据类型 list def app(self,p_object): #派生出新的 append功能 if not isinstance ...

  10. &lbrack;搬运&rsqb;CORBA中BOA和POA的含义

    先来BOA,搬自:http://www.cl.cam.ac.uk/research/dtg/attarchive/omniORB/doc/2.8/omniORB2/node6.html The Bas ...