加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

linux – perl sysopen可以打开文件进行原子写入吗?

发布时间:2020-12-14 01:06:07 所属栏目:Linux 来源:网络整理
导读:在阅读APUE(第3版)一书时,我遇到了开放式系统调用及其允许用户使用O_APPEND模式打开文件进行写入原子操作的能力,这意味着多个进程可以写入文件描述符并且内核确保写入的数据通过多个进程到单个文件,不重叠,所有行都完好无损. 在使用C/C++程序成功进行开放式
在阅读APUE(第3版)一书时,我遇到了开放式系统调用及其允许用户使用O_APPEND模式打开文件进行写入原子操作的能力,这意味着多个进程可以写入文件描述符并且内核确保写入的数据通过多个进程到单个文件,不重叠,所有行都完好无损.

在使用C/C++程序成功进行开放式系统调用试验后,我能够对其进行验证,并且它就像书中描述的那样工作.我能够启动多个写入单个文件的进程,并且所有行都可以将w.r.t计入其进程PID.

我希望与perl sysopen一起观察相同的行为,因为我在工作中有一些任务可能会受益于这种行为.尝试了,但实际上没有用.当我分析输出文件时,我能够看到竞争条件的迹象(可能),因为有很多次交错行.

问题:perl sysopen调用与linux的开放系统调用不一样吗?是否有可能通过多个进程将单一文件的这种类型的原子写操作实现?

编辑:添加C代码和用于测试的perl代码.

C/C++代码

int main(void)
{
  if ((fd = open("outfile.txt",O_WRONLY|O_CREAT|O_APPEND)) == -1) { 
    printf ("failed to create outfile! exiting!n");
    return -1;
  }

  for (int counter{1};counter<=MAXLINES;counter++)
  { /* write string 'line' for MAXLINES no. of times */
    std::string line = std::to_string(ACE_OS::getpid())
      + " This is a sample data line ";
    line += std::to_string(counter) + " n";
    if ((n = write(fd,line.c_str(),strlen(line.c_str()))) == -1) {
      printf("Failed to write to outfile!n";
    }
  }
  return 0;
}

Perl代码

#!/usr/bin/perl

use Fcntl;
use strict;
use warnings;

my $maxlines = 100000;

sysopen (FH,"testfile",O_CREAT|O_WRONLY|O_APPEND) or die "failed sysopenn";
while ($maxlines != 0) {
  print FH "($$) This is sample data line no. $maxlinesn";
  $maxlines--;
}
close (FH);
__END__

更新(初始故障排除后):

感谢下面答案中提供的信息,我能够让它运作起来.虽然我遇到了一些缺失行的问题,这些行是由于我用O_TRUNC打开每个进程的文件引起的,我不应该这样做,但最初错过了它.经过一些仔细的分析 – 我发现了问题并纠正了它.一如既往 – linux永远不会让你失望:)

这是我用来启动进程的bash脚本:

#!/bin/bash

# basically we spawn "$1" instances of the same 
# executable which should append to the same output file.

max=$1
[[ -z $max ]] && max=6
echo "creating $max processes for appending into same file"

# this is our output file collecting all
# the lines from all the processes.
# we truncate it before we start
>testfile

for i in $(seq 1 $max)
do
    echo $i && ./perl_read_write_with_syscalls.pl 2>>_err & 
done

# end.

从输出文件验证:

[compuser@lenovoe470:07-multiple-processes-append-to-a-single-file]$ ls -lrth testfile 
-rw-rw-r--. 1 compuser compuser 252M Jan 31 22:52 testfile
[compuser@lenovoe470:07-multiple-processes-append-to-a-single-file]$ wc -l testfile 
6000000 testfile
[compuser@lenovoe470:07-multiple-processes-append-to-a-single-file]$ cat testfile |cut -f1 -d" "|sort|uniq -c
1000000 (PID: 21118)
1000000 (PID: 21123)
1000000 (PID: 21124)
1000000 (PID: 21125)
1000000 (PID: 21126)
1000000 (PID: 21127)
[compuser@lenovoe470:07-multiple-processes-append-to-a-single-file]$

观察:

令我惊讶的是,系统上没有任何等待平均负载 – 根本没有.我没想到.我相信内核必须已经处理过,但不知道它是如何工作的.我有兴趣了解更多相关信息.

这可能是什么应用?

我做了很多文件来进行文件协调,我们(在工作中)总是需要解析大量的数据文件(例如30gb – 50gb).有了这个工作 – 我现在可以做并行操作,而不是我以前的方法,包括:散列文件1,然后散列文件2,然后比较2个文件中的键,值对.现在我可以并行执行散列部分并缩短所需的时间 – 甚至更进一步.

谢谢

解决方法

打开或sysopen无关紧要;关键是使用syswrite和sysread而不是print / printf / say / etc和readline / read / eof / etc.

syswrite映射到单个write(2)调用,而print / printf / say / etc可能导致多次调用write(2)(即使启用了autoflush).[1]

sysread映射到单个read(2)调用,而readline / read / eof / etc可能导致多次调用read(2).

因此,通过使用syswrite和sysread,如果您使用POSIX系统,那么您将受到POSIX提供的关于这些调用(无论它们可能是什么)的所有保证.

>如果使用print / printf / say / etc,并将写入限制为小于(显式或自动)刷新之间缓冲区的大小,则会进行一次write(2)调用.旧版Perl中的缓冲区大小为4 KiB,默认情况下,在新版本的Perl中,缓冲区大小为8 KiB. (构建perl时确定大小.)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读