1

我在一个文件(“ phrases”)中有一个短语列表,每个文件都在自己的行中。

我还有另一个文件,其中包含一个单词列表,每个单词占一行(“ words”)。

我希望在“”中的每个短语的末尾附加一个星号phrases,它以“”中列出的单词开头words

例如:

文件“ phrases”:

gone are the days
hello kitty
five and a half
these apples are green

文件“ words”:

five
gone

操作后“”中的预期结果phrases

gone are the days *
hello kitty
five and a half *
these apples are green

到目前为止我所做的是:

parallel -j0 -a words -q perl -i -ne 'print "$1 *" if /^({}\s.*)$/' phrases

但这会截断文件,有时(并非总是)给我这个错误:

无法删除短语:没有这样的文件或目录,跳过文件。

因为编辑将同时进行,所以我的意图是只搜索和替换那些以单词开头的行,而其他行保持不变。否则parallel并发执行会互相覆盖。

我也对其他并发方法持开放态度。

4

3 回答 3

1

为什么这个问题不是并行进程调度?

试想一下值的内部依赖链,这些值需要在[SEQ]流程输出端以给定的、严格控制的方式输出。

事实 1)虽然很容易通过使用
语法来分拆多个进程以使其在 shell 级别强制执行,但这并不意味着这种共同的每一种情况现有的流程确实可以免费实现顺畅和智能的“恰巧” ,甚至是真正的流程调度。[CONCURRENT][PARALLEL]

事实 2 )必须以纯
方式处理,因为自然顺序 ( ) 很重要并且必须保留,即使对于基于文件的输出也是如此。file:phrases[SERIAL]SEQ

事实 3 )
每个基于文件的文件在设计上都是一个纯[SERIAL]进程,既不是“只是” [CONCURRENT]也不是真正[PARALLEL]的,直到有人发明了一种方法,如何使硬盘读取设备的磁头在某个时刻处于多个位置的时间(这甚至远远超出了亚原子尺度上的量子纠缠和叠加技巧和魔法)。

事实 4
当然,可以想象某种用于并发处理的空间,一旦知道[SEQ]来自 a 的 -read-input file:phrases,如果处理多个([SEQ]-operated )查找,则可能会出现一些加速 -但是,同样,基于一个条件,有两种资源(多个查找同时发生,如果不是所有并发进程都能无缝执行,对流程没有任何不利影响)并且所有这些都必须具有“预缓存”整个-“已知”-静态内容file:words(否则将无济于事),以便在某种程度上能够从下一个(再次[SEQ])纯--中逃脱[SERIAL] fileIO[SEQ]-ordered 和并发容量限制了第一个单词匹配查找的重新处理,现在某种形式的语法迫切需要从多个words-crawling 进程中发生。


一个人可以很容易地支付比以往任何时候都多的方式:

不正确甚至幼稚​​的流程调度可能并且确实会引入附加成本,这是以前在纯[SERIAL]代码执行中从未见过的。即使是最轻量级的并发框架附加成本(如果许多并发代码执行似乎变得势在必行,不惜任何代价,这些成本确实会随着 N 增加)

仔细阅读有关阿姆达尔定律的详细信息,最好结合其现代批评,包括现代重新制定,其中包括严格的开销附加成本和代码执行的原子单元不可分割性,独立于数量可用的处理器。尽管早在 50 年前就有了它的最初形式,但现代大规模并行代码执行生态系统仍然无法更好地从这一无人能逃脱的主要定律的依赖关系中学习。

因此,请始终检查[SEQ]问题依赖链中的所有依赖关系。因此,在梦想性能之前
,请务必检查所有附加开销。[PAR]

于 2017-11-27T15:16:25.200 回答
1
perl -i -pe'
    BEGIN {
       my $words_qfn = shift(@ARGV);
       open(my $words_fh, "<", $words_qfn) or die $!;
       chomp( my @words = <$words_fh> );
       my $alt = join "|", map quotemeta, @words;
       $re = qr/^(?:$alt)\b.*\K/;
    }
    s/$re/ */;
' words phrases
于 2017-11-27T15:47:42.647 回答
1

这不适合并行处理,因为到目前为止,您可以执行的最昂贵的操作(通常)是从磁盘读取。CPU要快得多。

您的问题不是 CPU 密集型的,因此并行运行不会获得太多优势。更糟糕的是 - 正如您所发现的 - 您会引发可能导致文件破坏的竞争条件。

实际上,磁盘 IO 是从磁盘以块(多个 K)的形式完成的,这些块被提取到缓存中,然后以您可以假装read逐字节工作的方式馈送到操作系统。

如果您按顺序读取文件,预测性提取可以让操作系统更高效地处理它,并且尽可能快地将整个文件拉入缓存,从而大大加快处理速度。

尝试并行化和交错这个过程充其量是没有效果的,而且会使事情变得更糟。

因此,考虑到这一点,您最好不要尝试并行,而是:

#!/usr/bin/env perl

use strict;
use warnings;

open ( my $words_fh, '<', 'words' ) or die $!; 
my $words = join '|', map { s/\n//r } <$words_fh>;
   $words = qr/\b(?:$words)\b/;
close ( $words_fh );

print "Using match regex of: ", $words, "\n";

open ( my $phrases_fh, '<', 'phrases' ) or die $!;
while ( <$phrases_fh> ) { 
  if (m/$words/) {
      s/$/ */;
  }
  print;
} 

将输出重定向到所需位置。

最昂贵的一点是文件的读取——它只做一次。为每个搜索词的同一行重复调用正则表达式引擎也会很昂贵,因为您将执行 N * M 次,其中 N 是单词数,M 是行数。

因此,我们编译一个单一的正则表达式,并使用零宽度\b单词边界标记匹配它(因此它不会匹配子字符串)。

注意 - 我们不引用words- 这可能是错误或功能的内容,因为这意味着您可以将正则表达式添加到组合中。(当我们编译正则表达式时,这可能会中断)。

如果你想确保它是“字面的”,那么:

my $words = join '"', map { quotemeta } map { s/\n//r } <$words_fh>; 
于 2017-11-27T17:53:49.830 回答