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

并发附加到使用Perl的同一个文件

发布时间:2020-12-15 21:27:01 所属栏目:大数据 来源:网络整理
导读:我需要升级Perl CGI脚本,用户必须完成3个步骤.每个步骤完成后,脚本将记录用户完成的步骤.记录这一点很重要,所以我们可以向用户证明他们只是完成了第一步,没有完成所有三个步骤,例如. 现在,脚本正在为CGI脚本的每个实例创建1个日志文件.因此,如果UserA执行步
我需要升级Perl CGI脚本,用户必须完成3个步骤.每个步骤完成后,脚本将记录用户完成的步骤.记录这一点很重要,所以我们可以向用户证明他们只是完成了第一步,没有完成所有三个步骤,例如.

现在,脚本正在为CGI脚本的每个实例创建1个日志文件.因此,如果UserA执行步骤1,则UserB执行步骤1,然后步骤2,然后步骤3 – 然后UserA完成步骤2和步骤3日志文件的顺序.

LogFile.UserA.Step1
LogFile.UserB.Step1
LogFile.UserB.Step2
LogFile.UserB.Step3
LogFile.UserA.Step2
LogFile.UserA.Step3

日志文件以当前时间戳,随机数和进程PID命名.

这样做可以防止同一个文件被写入不止一次,但目录可以快速获得数千个文件(每个文件只包含几个字节).有一个旋转和压缩这些日志的过程,但是它已经落在我身上,使脚本每天只记录一个文件,以减少正在创建的日志文件的数量.

基本上,日志文件将具有文件名中的当前日期,并且CGI脚本需要写入日志的任何时间都将附加到该日期的一个日志文件中,无论用户是什么,还是进行什么步骤.

没有什么需要阅读日志文件 – 唯一会发生的事情是CGI脚本的追加.日志轮换将在7天或更长时间的日志文件上运行.

我的问题是,处理并发附加到这个日志文件的最好方法是什么?我需要锁定吗?我在Perl Monks上发现了this page,似乎表明“当多个进程正在写入同一个文件,并且所有这些文件都打开以附加文件时,数据不会被覆盖.

我知道,只是因为可以做到并不意味着我应该,但在这种情况下,什么是最安全的最佳做法呢?

概要:

>并发附加到同一个文件
>每个附加到文件只是一行,少于50个字符
>订单没关系

谢谢!

解决方法

是的,使用羊群.

下面是一个示例程序,从典型的前沿开始:

#! /usr/bin/perl

use warnings;
use strict;

use Fcntl qw/ :flock /;

然后我们指定日志的路径和将运行的客户端的数量:

my $log = "/tmp/my.log";
my $clients = 10;

要记录消息,请以附加模式打开文件,以便所有写入都会自动结束.然后调用鸡群等待我们的独家访问日志.一旦我们起床,写信息并关闭手柄,自动释放锁.

sub log_step {
  my($msg) = @_;

  open my $fh,">>",$log or die  "$0 [$$]: open: $!";
  flock $fh,LOCK_EX      or die  "$0 [$$]: flock: $!";
  print $fh "$msgn"      or die  "$0 [$$]: write: $!";
  close $fh               or warn "$0 [$$]: close: $!";
}

现在fork $客户端子进程通过三个步骤之间的随机间隔:

my %kids;
my $id = "A";
for (1 .. $clients) {
  my $pid = fork;
  die "$0: fork: $!" unless defined $pid;

  if ($pid) {
    ++$kids{$pid};
    print "$0: forked $pidn";
  }
  else {
    my $user = "User" . $id;
    log_step "$user: Step 1";
    sleep rand 3;
    log_step "$user: Step 2";
    sleep rand 3;
    log_step "$user: Step 3";
    exit 0;
  }

  ++$id;
}

不要忘记等待所有的孩子退出:

print "$0: reaping children...n";
while (keys %kids) {
  my $pid = waitpid -1,0;
  last if $pid == -1;

  warn "$0: unexpected kid $pid" unless $kids{$pid};
  delete $kids{$pid};
}

warn "$0: still running: ",join("," => keys %kids),"n"
  if keys %kids;

print "$0: done!n",`cat $log`;

样品输出:

[...]
./prog.pl: reaping children...
./prog.pl: done!
UserA: Step 1
UserB: Step 1
UserC: Step 1
UserC: Step 2
UserC: Step 3
UserD: Step 1
UserE: Step 1
UserF: Step 1
UserG: Step 1
UserH: Step 1
UserI: Step 1
UserJ: Step 1
UserD: Step 2
UserD: Step 3
UserF: Step 2
UserG: Step 2
UserH: Step 2
UserI: Step 2
UserI: Step 3
UserB: Step 2
UserA: Step 2
UserA: Step 3
UserE: Step 2
UserF: Step 3
UserG: Step 3
UserJ: Step 2
UserJ: Step 3
UserE: Step 3
UserH: Step 3
UserB: Step 3

请记住,订单将与运行不同.

(编辑:李大同)

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

    推荐文章
      热点阅读