Как заменить несколько шаблонов в одном файле, основываясь на первом слове строки?
У меня есть список фраз в одном файле (" 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
параллельное выполнение перезапишет друг друга.
Я открыт для других одновременных методов.
3 ответа
Это не подходит для параллельной обработки, потому что самая дорогая операция, которую вы можете сделать - обычно - чтение с диска. Процессор намного быстрее.
Ваша проблема не сильно загружает процессор, поэтому вы не получите большого преимущества от параллельной работы. И что еще хуже - как вы обнаружили - вы вызываете состояние гонки, которое может привести к засорению файлов.
Практически говоря, дисковый ввод-вывод выполняется частями - несколько 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>;
Почему эта проблема не параллельное планирование процессов?
Просто представьте себе внутреннюю цепочку зависимостей значений, которые необходимы для вывода в заданный, строгий [SEQ]
-контролируемый путь в самом конце процесса вывода.
Факт № 1)
хотя очень легко выделить более одного процесса, используя синтаксис gnu -rallel, чтобы сделать его обязательным для выполнения на уровне оболочки, это вовсе не означает, что каждый случай таких сосуществующих процессов допускает гладкое и умное "просто" по совпадению [CONCURRENT]
или даже правда- [PARALLEL]
планирование процесса бесплатно.
Факт № 2)
file:phrases
должны быть обработаны в чистом [SERIAL]
образом, как естественный порядок (SEQ
) имеет значение и должна быть сохранена даже для результирующего файлового вывода.
Факт № 3)
каждый файл на основе [SERIAL]
процесс, ни "просто"- [CONCURRENT]
ни правда- [PARALLEL]
До тех пор, пока не изобретен способ, как сделать так, чтобы головки устройства чтения жесткого диска в один момент времени находились в нескольких местах (что значительно превосходит даже квантовую запутанность, трюки суперпозиции и магию в субатомном масштабе).
Факт № 4)
Конечно, можно представить себе какое-то пространство для параллельной обработки, как только [SEQ]
-читание от file:phrases
известно, где может произойти некоторое ускорение, если более одного ([SEQ]
поиск) будет обработан - но, опять же, на основе условия, что есть оба ресурса (для одновременного выполнения нескольких поисков, без какого-либо неблагоприятного влияния на поток процессов в случае, если не все параллельные процессы получают выполняется без проблем), и все они должны иметь "предварительно кэшированное" все "известное" статическое содержимое file:words
(иначе это не поможет), чтобы как-то сбежать от следующего ([SEQ]
опять) чисто- [SERIAL]
fileIO
- [SEQ]
упорядоченная повторная обработка с ограничением одновременной пропускной способности при поиске соответствия по первому слову, в настоящее время настоятельно необходимая форма синтаксиса gnu-параллелизма для более чем одного words
-ползание процессов.
Можно легко заплатить больше, чем можно было бы получить от:
Неправильное или даже наивное планирование процессов может и действительно приводит к дополнительным расходам, которых никогда не было в [SERIAL]
выполнение кода. Даже самые легкие дополнительные издержки платформ параллелизма (и эти затраты масштабируются с N, если многие исполнения параллельного кода оказываются крайне материализованными, буквально любой ценой)
Пожалуйста, внимательно прочитайте подробную информацию о Законе Амдала, лучше всего его современную критику, в том числе современную переформулировку, включающую как дополнительные надбавки к издержкам, так и неделимость кода при выполнении кода, не зависящую от числа процессоры в наличии. Несмотря на свою первоначальную формулировку 50 лет назад, современные массивно-параллельные экосистемы исполнения кода все еще не могут лучше учиться из зависимостей этого основного закона, от которых никто никогда не сможет избежать.
Поэтому всегда проверяйте все [SEQ]
-зависимости в цепочке зависимостей проблемы.
Поэтому всегда проверяйте все [PAR]
накладные расходы, прежде чем даже мечтать о производительности.
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