Я использую следующие ожидаемые строки возврата из 5 символов:
while (glob '{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}'x5) {
print "$_\n";
}
но он возвращает только 4 символа:
anbc
anbd
anbe
anbf
anbg
...
Однако когда я уменьшу количество символов в списке:
while (glob '{a,b,c,d,e,f,g,h,i,j,k,l,m}'x5) {
print "$_\n";
}
возвращается правильно:
aamid
aamie
aamif
aamig
aamih
...
Может кто-нибудь сказать мне, что мне здесь не хватает, есть ли какой-то предел? или есть ли способ обойти это?
Если это делает никакой разницы, она возвращает тот же результат в обоих perl 5.26
иperl 5.28
Ответы:
У всего есть некоторые ограничения.
Вот чистый модуль Perl, который может сделать это для вас итеративно. Он не генерирует весь список сразу, и вы сразу начинаете получать результаты:
источник
NestedLoops
также может быть использованы:use Algorithm::Loops qw( NestedLoops ); NestedLoops([ ([ 'a'..'z' ]) x 5 ], sub { say join '', @_ } );
(Ответ на предыдущий вопрос по ОП отметил , что они могли бы использовать это , если они выбегали из памяти ...)glob
Первым создает все возможные расширения имен файлов, поэтому он будет первым генерировать полный список из оболочки стиль Глоб / шаблона это дается. Только тогда он будет перебирать его, если он используется в скалярном контексте. Вот почему так трудно (невозможно?) Избежать итератора, не исчерпав его; см этого поста .В вашем первом примере это 26 5 строк (
11_881_376
), каждая длиной пять символов. Итак, список из ~ 12 миллионов строк, с общим количеством (наивных) свыше 56 МБ ... плюс накладные расходы для скаляра, который, я думаю, составляет минимум 12 байтов или около того. Таким образом, порядка 100 МБ, по крайней мере, прямо в одном списке. †Я не знаю каких-либо формальных ограничений на длину вещей в Perl (кроме как в регулярных выражениях), но
glob
делает ли это все внутренне и должны быть недокументированные ограничения - возможно, некоторые буферы где-то переполнены, внутренне? Это немного чрезмерно.Что касается способа обойти это - генерировать этот список из 5-ти символьных строк итеративно, вместо того, чтобы позволять
glob
сворачивать свою магию за кулисы. Тогда это абсолютно не должно иметь проблемы.Тем не менее, я нахожу все это немного большим для комфорта, даже в этом случае. Я действительно рекомендую написать алгоритм, который генерирует и предоставляет один элемент списка за раз («итератор»), и работать с этим.
Есть хорошие библиотеки, которые могут сделать это (и многое другое), некоторые из которых Algorithm :: Loops, рекомендованные в предыдущем посте по этому вопросу (и в комментарии), Algorithm :: Combinatorics (тот же комментарий),
Set::CrossProduct
из другого ответа Вот ...Также обратите внимание, что, хотя это разумное использование
glob
, библиотека предназначена для работы с файлами. Помимо неправильного использования в принципе, я думаю, что он проверит каждое из (~ 12 миллионов) имен на правильность записи ! (См. Эту страницу .) Это много ненужной работы с диском. (И если бы вы использовали «globs», как*
или?
в некоторых системах, он возвращает список только с теми строками, которые действительно имеют файлы, так что вы спокойно получили бы другие результаты.)† Я получаю 56 байтов за размер скаляра из 5 символов. В то время как это для объявленной переменной, которая может занять немного больше, чем анонимный скаляр, в тестовой программе со строками длины 4 фактический общий размер действительно на порядок больше, чем вычисляемый наивно. Так что реальная вещь вполне может быть порядка 1 Гб за одну операцию.
Обновление Простая тестовая программа, которая генерирует этот список из 5-символьных длинных строк (используя тот же
glob
подход), выполнялась в течение 15 минут на компьютере серверного класса и занимала 725 МБ памяти.Это произвело правильное количество фактических 5-символьных длинных строк, казалось бы, правильных, на этом сервере.
источник
glob
. (Для этого понадобится простой, другой алгоритм. Возможно, то, что я написал в вашем предыдущем вопросе? Это хорошая отладка - если вы можете получить этот список без проблем, тогда вы знаете, что здесь вводятся ограничения.) Я добавил некоторые оценки размера что яtime perl -MDevel::Size=total_size -wE'$chs = join ",", "a".."z"; @items = glob "{$chs}"x5; say STDERR "Total memory: ", total_size(\@items)/(1024**2), " Mb"
... и позвольте мне проверить ... теперь он работает через 30 секунд, что подтверждает это, учитывая, как кеширование работает здесь. Я также проверил RSS с внешними инструментами, пока он шел.26**5
)