Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 读取fifo时的重叠输出:如何修复/避免这种情况?_Perl_Pipe_Fifo_Rhel5_Overlapped Io - Fatal编程技术网

Perl 读取fifo时的重叠输出:如何修复/避免这种情况?

Perl 读取fifo时的重叠输出:如何修复/避免这种情况?,perl,pipe,fifo,rhel5,overlapped-io,Perl,Pipe,Fifo,Rhel5,Overlapped Io,我试图从2个文件中聚合数据,因此我决定通过单独的写入进程将数据发送到指定的fifo,并启动单独的读取进程来读取和处理聚合的数据。所有的读/写操作都发生在一个ramdisk(/dev/shm)上,这个ramdisk方便地大到大约100GB 这是一个工作文件,我确保写入fifo的每条数据线都少于512字节,这样管道就可以保留其原子行为 但在尝试了多次运行之后,我发现读卡器进程正在接收重叠的输出,当我尝试从每个进程传输1000多万行时,这种情况就开始发生了。我的每个数据行都以新行终止 我在“+>fif

我试图从2个文件中聚合数据,因此我决定通过单独的写入进程将数据发送到指定的fifo,并启动单独的读取进程来读取和处理聚合的数据。所有的读/写操作都发生在一个ramdisk(/dev/shm)上,这个ramdisk方便地大到大约100GB

这是一个工作文件,我确保写入fifo的每条数据线都少于512字节,这样管道就可以保留其原子行为

但在尝试了多次运行之后,我发现读卡器进程正在接收重叠的输出,当我尝试从每个进程传输1000多万行时,这种情况就开始发生了。我的每个数据行都以新行终止

我在“+>fifo”进行写入。这里不使用syscalls,只使用normalopen获取文件句柄并尝试逐行处理数据

我怎样才能开始调查这件事。有什么想法吗

非常感谢

自2019年4月29日起更新:

请注意,我的循环现在正在使用系统调用。以前我没有使用它们,但最终决定使用它们

同样的事情也可以通过让两个进程写入一个文件来实现,但需要注意的是,这只适用于符合POSIX标准的文件系统,或者如果没有,可以将日志文件(多个进程将执行写入)保存在RAMDISK中,因为它也可以工作。NFS驱动器超出范围,因为它不符合POSIX标准,而且这种技术在它上不起作用

因此,如果我们谈论FIFO与文本文件,那么多个进程读取/写入文件要比多个进程读取/写入FIFO快

对于即将到来的读者,这里是我的writer&reader过程代码。如何设计代码以合并这些子例程取决于您。有很多方法可以做到这一点

希望它有用

编写器进程

  write_log => sub {
    my ($filehandle, $log_message) = @_;
    select $filehandle ; $|++;
    syswrite ($filehandle, $log_message, length($log_message))
      or die "write_log: syswrite fail!\n";
  },
读卡器进程:

  read_log => sub
  {
    # In my endless reading loop,
    # if I detect keyword END 2 times (as 
    # i have 2 processes), I exit the reading loop
    # and do further operations.
    #
    my ($end_check_value) = @_;

    sysopen (FH,$logfile, O_CREAT|O_RDONLY)
      or die "($$) read_log: Failed to sysopen\n";

    my ($h, $end) = (undef,0);

    select FH ; $|++ ;

    print STDOUT get_ts().'|'."($$) read_log: now tailing logfile with check count $end_check_value\n";

    for (;;)
    {
      while (my $line = <FH>)
      {
        chomp $line;
        $end++ if $line =~ m/END/g;
        last if $end == $end_check_value;
        my $key = (split(/\s/,$line))[0];
        $h->{$key}++;
      }

      sleep(1) ; seek (FH,0,1);

      # break out of for loop if we
      # have collected the 'END' tags
      # from all worker processes
      if ($end == $end_check_value)
      {
        print STDOUT get_ts().'|'."($$) read_log: breaking for loop ",
                     "with end_check: $end_check_value\n";
        last;
      }
    } close (FH);
  },
以下是FIFO的性能统计数据,其中多个进程向FIFO写入25000000行,读卡器进程将它们读回散列。平均需要25-30分钟。它比写入文件的进程慢

test string is 141 bytes long
20190426-10:25:13.455|28342|2-test-fifo.pl: Starting..
20190426-10:25:13.456|28345|CHILD starting (read_and_hash)
20190426-10:25:13.456|28345|READ_AND_HASH now hashing files
20190426-10:25:14.458|28346|CHILD starting (s1_data_gather)
20190426-10:25:14.458|28346|Working on sit1 data..
20190426-10:25:14.458|28347|CHILD starting (s2_data_gather)
20190426-10:25:14.458|28347|Working on sit2 data..
20190426-10:48:48.454|28346|Finished working on S1 data..
20190426-10:48:48.457|28342|Reaped 28346
20190426-10:48:48.462|28345|read LAST line from S2 data
20190426-10:48:52.657|28347|Finished working on s2 data..
20190426-10:48:52.660|28342|Reaped 28347
20190426-10:48:52.669|28345|read LAST line from S2 data
20190426-10:48:53.130|28345|READ_AND_HASH finished hashing files
(read_n_hash): finished hashing. keys count
        s1 = 25000000
        s2 = 25000000
20190426-10:48:53.130|28345|starting comparison. doing source to target
20190426-10:49:49.566|28345|finished comparing source to target. now comparing target to source
20190426-10:50:45.578|28345|comparing target to source ends. finished
20190426-10:51:57.220|28342|Reaped 28345
20190426-10:51:57.220|28342|2-test-fifo.pl: Ending..

您可能必须为要写入的文件启用自动刷新。如果使用open()函数打开文件,而不是通过IO::File之类的OO接口打开文件,那么在成功打开文件(比如$fifo)后,您需要这样的代码

select $fifo;
$| = 1;
请注意,select()为打印选择输出文件句柄,这类文件不指定特定的文件句柄。如果要恢复到目标STDOUT,则在上述操作之后选择STDOUT,或者,要学究化:

my $oldfh = select $fifo;
$| = 1;
select $oldfh;

我不认为文件模式('+您在这里看到的可能是一个简单的并发产品。您假设读卡器及时从FIFO中提取数据。如果两个写卡器都有机会在读卡器再次尝试读取之前写入多条记录呢?如果FIFO通过写入部分达到容量呢?写入er将在写入过程中部分阻塞,然后读取器将有机会清空队列,但不能保证写入部分行的写入者将是下一个要写入的写入者。这将导致交错行

<> P>如果我关于自动填充的回答不能解决你的问题,你可能需要考虑这样写的交错的可能性。


如上面的评论所述,使用数据报套接字(SOCK_DGRAM)可能会更好而不是先进先出。这样,每条消息都是一个原子单元,没有交错的机会。

我会尝试一下,然后返回结果。如果它有效,我会接受你的答案作为解决方案。有一件事-打开时使用“啊,如果你在”Re“中读取文件,我想每次管道中没有更多数据时,你都会遇到EOF。”,这不是真的。读取将阻塞(或在非阻塞句柄上返回错误
EAGAIN
ewoodblock
)。当写入程序关闭句柄时,它确实会返回EOF。是的,我在考虑这样的情况,即您正在跟踪真实文件的尾部。但是写入程序是否在写入之间关闭FIFO?这是一个命名的FIFO,因此这种行为是可能的。我们需要查看代码。文件句柄上的选择非常有效。现在没有更多的重叠数据了输出中的nes。感谢分享您的知识。我真的很感激。答案被接受并投票,因为这是正确的做法。干杯。这可能是一件棘手的事情。您能不能给我们看一下您的(相关)代码?
my $oldfh = select $fifo;
$| = 1;
select $oldfh;