【问题标题】:Prevent two or more instances of awk from simultaneously writing to the same file防止两个或多个 awk 实例同时写入同一个文件
【发布时间】:2018-11-23 17:12:00
【问题描述】:

awk 是否有任何内置支持来防止写入另一个 awk 实例已经写入的同一文件?

考虑以下几点:

$ # Create large input file
$ for i in {1..500000}; do echo "$i,$i,$i" >> /tmp/LargeFile.txt; done
$ # Launch two simultaneous instances of awk outputting to the same file
$ awk -F"," '{print $0}' /tmp/LargeFile.txt >> /tmp/OutputFile.txt & awk -F"," '{print $0}' /tmp/LargeFile.txt >> /tmp/OutputFile.txt &
$ # Find out how many fields are in each line (ideally 3)    
$ awk -F"," '{print NF}' /tmp/Output.txt | sort | uniq -c
          1 0
        553 1
       1282 2
     996412 3
       1114 4
        638 5

因此,两个 awk 实例同时将大量数据输出到同一个文件。理想情况下,输出文件每行应包含三个逗号分隔值,但由于两个实例同时写入同一个文件,因此某些行可能有超过 3 个逗号分隔值,而有些行可能少于 3 个。

示例损坏的输出文件:

1,1,1   < 1's from from first instance of awk
2,2,2   < 2's from from first instance of awk
3,3,3   < 3's from from first instance of awk
1,1,1   < 1's from from second instance of awk
2,2,2   < 2's from from second instance of awk
4,4,4   < 4's from from first instance of awk
5,5,5   < 5's from from first instance of awk
3,3,3   < 3's from from second instance of awk
4,6,6,4,6   < corrupted input as both instances tried to write to this line at the same time
4
7,7,7   < 7's from from first instance of awk

有什么好的简单的方法可以防止这种情况发生吗?

编辑 - 从实际场景中添加更多细节:

每个 awk 实例所做的处理将更像这样:来自其他进程的数据不断写入文件,例如每 5 分钟有一个新文件。将调用 awk 的多个实例以按设定的时间间隔(例如每 30 分钟)处理/聚合数据。

cat SomeFilesWithLotsOfData | awk '
{
    # process lots of data which takes a lot of time
    # build up associate arrays based on input
}
END {
    # Output processed data which takes little time
    # Loop over associative arrays and output to persistent files
}'

假设处理部分(在 END 语句之前)需要 30 分钟才能完成(哇,那是很长的时间,但让我们用它来说明一下)。可以实例化同一 awk 脚本的第二个实例,以在第一个实例结束之前处理带有数据的新批次文件,并且它需要将其处理后的数据输出到与前一个实例相同的文件中。每个 awk 实例输出到的输出文件的确切数量取决于输入(即,它基于输入记录中的特定字段)。我不想在处理输入之前锁定所有可能的输出文件,因为我不知道哪个 awk 实例将首先完成处理。所以目前我计划在 END 开头创建一个锁并在 END 之后解锁它,但是我的实现有点笨拙,所以我正在寻找一种更好的方法。

【问题讨论】:

  • 可能有一些方法可以防止这种情况发生。 1-awk 2- 让第一个命令完成,然后它会自动进入第二个命令,然后你的文件将被连接起来。 2-如果您想在后台运行它们,则使用不同的输出文件,一旦它们完成,然后将它们连接起来或将它们写入同一个文件中。如果有人对您有帮助,请告诉我?
  • 感谢 RavinderSingh13。我不能保证这两个 awk 进程不会同时运行,我希望避免在最后连接文件的额外复杂性(在我的实际场景中实现起来很复杂)。所以我希望 awk 可能有一些不错的内置功能。
  • 正如已经建议的那样,您为什么不编写 2 个不同的文件,然后简单地 cat 将它们转换为 1 个输出?老实说,这样做不会有任何混淆。
  • 您不能只使用sempidlock 来确保只有一个awk 实例正在运行吗?否则你可以在文件上使用锁来避免冲突:lockfile 命令可以帮助你
  • 写入多个文件然后将它们连接起来的困惑在于,实际上每个 awk 实例可能正在写入的输出文件数量不定。在我的示例中只有两个,但实际上每个 awk 实例会有很多,并且每个文件都需要保护。 awk 如何使用 lockfile 来保护文件?

标签: file awk locking


【解决方案1】:

Quick-and-dirty way to ensure only one instance of a shell script is running at a time也有类似的问题

如果您的系统上存在该命令,flock(1) 解决方案可能是最简单的。

一种选择是简单地包装 所有 awk 脚本的调用:

flock -x /var/lock/myscriptlockfile awk ...

这将序列化 awk 脚本的调用,以便一次只能运行一个。您可以调整 flock 调用,使其在一段时间后终止,而不是永远等待,以决定是稍后重试还是跳过。

要允许脚本的多个副本运行但一次只允许一个副本写入,您可以调整此解决方案以从您的 END 中调用 flock 以将所谓的“关键部分”包装为类似:

awk 300>/var/lock/myscriptlockfile '
    # ...
    END {
        system("flock -x 300");
        # critical section
        system("flock -u 300");
    }
'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-04
    • 1970-01-01
    • 2013-01-26
    相关资源
    最近更新 更多