LINUX.ORG.RU

какое-то дичайшее поведение perl-а при передаче за-tie-еного хэша из функции

 may-be-bug, , tie


0

3

принимаются в том числе и ответы «не использовать перл для программы длиннее 20 строчек», но вообще-то хочется узнать:

1. чего я не знаю в перле, раз такая очевидная конструкция у меня глючит

2. как это пофиксить побыстрому (куда-то передать ссылку вместо хэша и т.п.)... не применять же препроцессор, елки-палки?

итак, создадим bdb на 600МБ (это слегка тормозит, но это нормально)

#!/usr/bin/perl -W

use DB_File;

my %result;
tie %result, 'DB_File', 'test.bdb', O_RDWR|O_CREAT, 0666, $DB_BTREE ;

for(my $i=1; $i<12345678; $i++ )
{
  warn( $i ) if $i%100000 eq 0;
  $result{$i} = 12345678 - $i;
}

далее читаем 1 запись из этого файла:

#!/usr/bin/perl -W

use DB_File;
use strict;

sub hash_from_file($)
{
  my ($file) = @_;
  my %result;
  tie %result, 'DB_File', $file, O_RDWR|O_CREAT, 0666, $DB_BTREE ;
  return %result;
}

my %result;

if( exists($ARGV[0]) )
{
  print "hash_from_file\n";
  %result = hash_from_file('test.bdb');
}
else
{                                                            
  # делаем то же, что hash_from_file, только без вызова этой функции
  tie %result, 'DB_File', 'test.bdb', O_RDWR|O_CREAT, 0666, $DB_BTREE ; 
}

print "starting\n";
print $result{'12344321'}."\n";

тут 2 варианта вызова скрипта:

1. если вызвать без аргументов, то читает мгновенно

2. но если вызвать с аргументом, то жрет много памяти (у меня на 32бит дошло до 2ГБ и далее стало свопиться) и цпу 100% одного ядра (причем в меньшем по размеру примере через примерно минуту такого поведения оно таки рожает правильный ответ)

почему, елки-палки?

★★★★★

Последнее исправление: www_linux_org_ru (всего исправлений: 2)

%result = hash_from_file('test.bdb');

Видимо здесь копируется весь хеш %result из функции, в %result вызывающей стороны. Поэтому на больших данных это долго и дорого по памяти. Передавайте по ссылке или как-то иначе работайте с данными.

outtaspace ★★★
()
Ответ на: комментарий от outtaspace

возможно

только непонятно, зачем копировать за-tie-еный хэш и почему он после копирования жрет памяти в разы больше, чем на диске

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от www_linux_org_ru

зачем копировать за-tie-еный хэш

«What you return when you do that is a COPY of the hash contents, and that copy is NOT tied».

http://stackoverflow.com/questions/4047940/in-perl-how-can-i-return-a-tied-ha...

после копирования жрет памяти в разы больше, чем на диске

Накладные расходы языка, чтобы данные с диска поместить во внутреннее представление (причем еще и копируются несколько раз).

outtaspace ★★★
()
Ответ на: комментарий от anonymous

не вижу логики выдавать *испорченную* копию

до какой-то степени логичным было бы выдать хэш, затаенный (tie) к копии файла, но уж если этого не делается — то к тому же файлу

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от outtaspace

«What you return when you do that is a COPY of the hash contents, and that copy is NOT tied».

это объясняет что происходит, но не зачем оно происходит, и как я должен был до этого догадаться

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от anonymous

если уж не можешь сделать копию легкового автомобиля, так уж сделай копию ключей от его дверей и замка зажигания

ну или честно упади (die)

а мне вместо этого предлагают то, что на копию похоже, но весит 10 тонн и через мост проехать не может

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от www_linux_org_ru

Ты сейчаc рассуждаешь не с позиции скриптокодера, как мне кажется. Или во всяком случае не перлокодера, перл нормальным, или хотя бы языком общего назначения, вообще-то никогда не был.

anonymous
()
Ответ на: комментарий от www_linux_org_ru

как я должен был до этого догадаться

Меня это не интересует. Судя по коду, Perl ты знаешь плохо, возможно поэтому плохо с интуицией.

outtaspace ★★★
()
Ответ на: комментарий от slovazap

Это же самые язы языка, из надо знать, а не догадываться.

правда? и где эти азы описаны? ну там man page в каком-то минимальном их наборе или официальный туториал?

наличие ответа на so не может подтвердить точку зрения, что это азы

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от outtaspace

Меня это не интересует.

а я тут должен был спрашивать то, что тебя интересует? это *меня* интересует

Судя по коду, Perl ты знаешь плохо,

да

и применяю его только ради удобных регулярок, ну еще bla-bla-bla if a>0 тоже удобно, и хэши в бдб я надеялся что будут удобны — и в общем тут его удобства заканчиваются

мне интересны замечания к моему коду

вот еще вопросы (для чисто кодинга скриптов на 20 сточек):

1. почему надо писать use strict и ему нет ключа как -W

2. почему эта якобы замена sh & awk не может поддержать все операторы шелла (ну там >>, >, -nt (хотя это test, но остальные же перл поддерживает)) и не может парсить строку как awk  — мне часто приходится включать куски шелл-кода, это раздражает

3. как сделать чтобы f($a) напечатала «a=3» и $b=$a; f($b) напечатала «b=3» — на си/плюсах похожее можно сделать дефайном

4. у меня всегда проблема с кодировками, если я пытаюсь использовать перловый «сервис» на эту тему — и кое-кто где-то утверждал, что там это непросто (утверждал не неосилятор, а человек, предлагавший свои услуги платно)

5. впечатление такое, что ооп делалось на «отвяжись»; есть ли проверка количества аргументов методов? вообще проверка количества аргументов похоже единственное, что перл умеет хоть как-то проверять, да и то при ооп использовать невозможно

6. ну и как сделать проверку количества аргументов, если часть из них опциональны? чтобы f($a) и f($a, $b) — пожалуйста, но f($a, $b, $c) должна выдать ошибку во время компиляции или BEGIN

7. где приличная документация по языку? man pages ужасны

з.ы. про автовивификацию я не написал, но я сложные структуры данных в этом языке не использую (вполне ожидаемо будут грабли), так что меня это обходит стороной

www_linux_org_ru ★★★★★
() автор топика
Последнее исправление: www_linux_org_ru (всего исправлений: 4)
Ответ на: комментарий от anonymous

Ты сейчаc рассуждаешь не с позиции скриптокодера, как мне кажется

я не собираюсь предъявлять претензии типа «в перле нет параметрического полиморфизма», хотя, по-моему, он бы не повредил

но вот претензия типа «если какое-то странное действие совершается, уж дай варнинг в рантайме» вполне подходящая к скриптовому языку

уж варнинг-то на копирование затаейного хэша можно было бы дать, не? а еще лучше упасть

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от outtaspace

еще

8. почему warn печатает про номер строки и т.п., если строка заканчивается на \r ? я хочу сказать, что \r должна была бы вести себя как \n, но не ведет — это мешает сделать удобный выхлоп прогресса

к п.3 eval не предлагать (т.е. я и сам могу добиться похожего от f('a'), но мне нужен комфорт скриптового языка, т.к. f($a))

www_linux_org_ru ★★★★★
() автор топика
Последнее исправление: www_linux_org_ru (всего исправлений: 2)
Ответ на: комментарий от outtaspace

9. какого хрена я должен писать

use File::Basename;
use lib dirname(__FILE__);

вместо однобуквенного ключа комстроки? (ладно, я согласен на 2 буквы)

это что, скриптовый язык? у меня шаблон создания скрипта на 10 строчек (включая пустые), почти как на яве, вместо ожидаемого для скриптового языка «включил и поехал»

10. есть ли вариант для создания модуля, короче чем этот:

package foo;

use strict;
use Exporter;

our $VERSION     = 0.20151215;
our @ISA         = qw(Exporter);
our @EXPORT      = qw(foo);

(отмечу, что слово foo приходится писать 3 раза, или все равно 2 раза если название функции не совпадает с названием модуля — второй раз в имени файла)

www_linux_org_ru ★★★★★
() автор топика
Последнее исправление: www_linux_org_ru (всего исправлений: 4)
Ответ на: комментарий от www_linux_org_ru

если уж не можешь сделать копию легкового автомобиля, так уж сделай копию ключей от его дверей и замка зажигания

У тебя здесь списковый контекст, так что перл сделает тебе список, содержащий копии всех деталей, а на вызывающей стороне попытается собрать из них еще одну машину

annulen ★★★★★
()
Ответ на: комментарий от annulen

гм...

учти, что хэш там tied

у меня понимание tied hash как интерфейса к bdb с помощью фигурных скобочек (а-ля перегрузка квадратных скобочек с++), и отсюда похоже все мое возмущение и негодование

если подходить к хэшу как к фундаментальной структуре перла, на некоторое время чисто случайно, по временному стечению обстоятельств, привязанной к bdb, тогда его копирование с отвязкой становится осмысленным

но последний подход мне не нравится даже для скриптового языка — он отдает чем-то вроде хранения по очереди двух разных по сути целых чисел в одной целой переменной для экономии места

www_linux_org_ru ★★★★★
() автор топика
Последнее исправление: www_linux_org_ru (всего исправлений: 6)
Ответ на: комментарий от annulen

а вот привязку приёмника копирования копирование похоже *не разрушает*:

#!/usr/bin/perl -W

use DB_File;
use strict;

my %a;
my %b;
my %bb;

tie %a, 'DB_File', 'a.bdb', O_RDWR|O_CREAT, 0666, $DB_BTREE ;
tie %b, 'DB_File', 'b.bdb', O_RDWR|O_CREAT, 0666, $DB_BTREE ;

sub f()
{
  %a = ( 'x', 1, 'y', 2 );
  return %a;
}

%b = f();
untie %b; # на всякий случай -- не знаю, правильно ли это 

tie %bb, 'DB_File', 'b.bdb', O_RDWR|O_CREAT, 0666, $DB_BTREE ;
print "$bb{x} $bb{y}\n"; # output is "1 2"

т.е. получается привязка — это свойство не значения, а самой переменной? своеобразно; че-то как-то не похоже на динамические языки (я ожидал что привязка — это свойство значения, а не переменной)

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от annulen

У тебя здесь списковый контекст, так что перл сделает тебе список, содержащий копии всех деталей, а на вызывающей стороне попытается собрать из них еще одну машину

а на вызывающей стороне соберет то, что получится исходя из размеров мастерской для сборки и имеющихся там станков, вроде так получается?

www_linux_org_ru ★★★★★
() автор топика

если использовать return \%result, то

# time perl 2.pl
starting                                      
1357                                      
Real: 0.04s User: 0.04s System: 0.00s Percent: 93%% Cmd: perl 2.pl
# time perl 2.pl 1
hash_from_file                                        
starting                                      
1357                                      
Real: 0.04s User: 0.03s System: 0.00s Percent: 74%% Cmd: perl 2.pl 1
arto ★★
()
Ответ на: комментарий от www_linux_org_ru
package Foo;

use parent qw(Exporter);

use strict;
use warnings;

our @EXPORT_OK = qw(foo);

$VERSION опционально, далеко не всегда надо указывать. @EXPORT стараюсь не использовать, только @EXPORT_OK - «явное лучше неявного».

use warnings всегда и везде.

outtaspace ★★★
()
Ответ на: комментарий от www_linux_org_ru

вместо однобуквенного ключа комстроки? (ладно, я согласен на 2 буквы)

PERL5LIB. Все, Perl не для тебя.

у меня шаблон создания скрипта на 10 строчек

Если говорить о шаблонах, то достаточно много написано. Я когда-то использовал ToolSet, некоторые юзают common::sense.

outtaspace ★★★
()
Ответ на: комментарий от www_linux_org_ru

но последний подход мне не нравится даже для скриптового языка — он отдает чем-то вроде хранения по очереди двух разных по сути целых чисел в одной целой переменной для экономии места

Привыкни к мысли, что хэши и массивы всегда передаются по ссылке, кроме ситуаций когда ты *хочешь* их деградации в списковом контексте. Или используй объектно-ориентированный модуль, DBD::DBM например, который заставит тебя использовать ссылку.

annulen ★★★★★
()
Ответ на: комментарий от annulen

Привыкни к мысли, что хэши и массивы всегда передаются по ссылке, кроме ситуаций когда ты *хочешь* их деградации в списковом контексте.

это в плюсах так можно и нужно, потому что там возможна ссылка на const Something

а в перле передал хэш по ссылке и по ошибке изменил (особенно автовивификацией, гы-гы), и вуаля — баг

кстати, приличный скриптовый язык делал бы copy on write, т.е. позволял бы скопировать любой хэш мгновенно, а копии делал бы только при попытках изменения (а то и вообще бы делал далеко после 1-го изменения — т.е. сделал бы сначала структуру а-ля хэш поверх хэша, и только затем бы копировал)

какого хрена перл копирует хэш, да еще заtieнный, сразу?!

кстати: хорошие пункты для чеклиста скриптового языка:

1. copy on write для больших коллекций

2. отложенное копирование с помощью хэша поверх коллекции или похожих трюков

www_linux_org_ru ★★★★★
() автор топика
Последнее исправление: www_linux_org_ru (всего исправлений: 3)
Ответ на: комментарий от arto

если использовать return \%result,

и что-то такое я как-то прям подозревал... даже в топике написал «куда-то передать ссылку вместо хэша»

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от annulen

т.е. получается привязка — это свойство не значения, а самой переменной?

perldoc tie

где там про это?

и заодно где там ответ на вопрос на so?

или в документации это и не нужно, и так сойдет, перебьются как-нибудь?

кстати, на с++ была бы документация хотя бы на конструктор копирования

www_linux_org_ru ★★★★★
() автор топика
Последнее исправление: www_linux_org_ru (всего исправлений: 1)
Ответ на: комментарий от outtaspace

@EXPORT стараюсь не использовать, только @EXPORT_OK - «явное лучше неявного».

у меня обычно мелкие утилитки и модуль из состоит из одной одноименной ему функции, поэтому у меня все явно (и ясно)

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от www_linux_org_ru

Ясно, хорошо если так.

У меня жесточайший ынтырпрайз, сотни тысяч строк кода. Модули с десятками тысяч строк кода. Поэтому только @EXPORT_OK.

outtaspace ★★★
()
Ответ на: комментарий от Deleted

перловщик-джуниор ннада?)

Сейчас джуны не нужны, даже перспективные. Хотя плюшки хорошие, джун из моей команды осенью релоцируется в Ирландию.

outtaspace ★★★
()

о сколько открытий чудных у тебя будет если ты продолжишь использовать perl...

на старой работе приходилось им пользоваться. До сих пор посылаю лучи ненависти этому языку.

reprimand ★★★★★
()
Ответ на: комментарий от reprimand

я использую перл в рамках примерно того, как слепой ходит, держась за стену

хотя это, конечно, гарантию от открытий чудных не дает, но все же их не так уж много

вот почертыхаюсь с tie и смогу ее использовать, опять держась за стену

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от reprimand

ну и вообще если я правильно понимаю, идея привязки tie (это не тавтология) к переменной, а не к ее значению интересная (хотя, конечно, это надо было в первую очередь рассказывать)

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от outtaspace

PERL5LIB

а что делать, если у меня в 2-3 директориях лежат 2-3 версии моих скриптов, которым требуются *свои* же версии модулей?

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от www_linux_org_ru

какого хрена

Да да, какого хрена ты его выкопал? Смешно читать претензии: почему говно воняет? И никто не отвечает, ведь все перлоеды давно уже в нирване. wlor, перегрелся штоле?

anonymous
()
Ответ на: комментарий от reprimand

До сих пор посылаю лучи ненависти этому языку

Посылать лучи надо мудакам, вытащившим перл в продакшын. Сама наколенная поделка для генерации отчетов от сисадминс ни в чем не виновата.

anonymous
()
Ответ на: комментарий от outtaspace

Судя по коду, Perl ты знаешь плохо

мне самому интересно стало, почему я влепил там eq, где лучше ==

это место я скопипастил с другого (в котором была реальная проблема), а другое мгновенно написал после получасовой отладки куска кода шелла внутри перла и видимо не переключился на перл

еще раз скажу — шелл внутри перла не только раздражает, но похоже приводит к таким вот ляпам

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Да да, какого хрена ты его выкопал

а на каком языке ты будешь парсить плохо структурированные веб-странички (и похожее — куски ответов json там) регулярными выражениями с кодом?

я бы кстати с удовольствием парсил бы их чем-то уровнем повыше регулярных выражений, но peg и прочее тут вроде совсем не к месту, так что инструмента лучше я не знаю

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от www_linux_org_ru

а в перле передал хэш по ссылке и по ошибке изменил

Используй Readonly если боишься что-то случайно изменить

какого хрена перл копирует хэш

Он не копирует хэш, он разворачивает его в списковом контексте в список, как и положено. Дальше ты присваиваешь этот список другому хэшу, и он конструируется, интрепертируя этот список как пары ключ-значение

annulen ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

Парсить веб-странички регулярками? Это какая то специальная олимпиада? Даже если все так запущено, что только регекспы тащат, внезапно! они везде имеются. Признайся, что ты взял перл из-за do_foo if $bar. Ня! Руби не пробовал, например?

anonymous
()
Ответ на: комментарий от www_linux_org_ru

насчет документации забей на перлдок и смотри обычный perldoc.perl.org

но вообще простотой документации язык тоже не блещет. А убийственный «there is more than one way to do it» лично меня просто сводил с ума.

reprimand ★★★★★
()
Ответ на: комментарий от anonymous

Посылать лучи надо мудакам, вытащившим перл в продакшын.

мудаки тащат в продакшн всё, чем пользуется народ

Начали пользоваться поделкой финского студента - потащили в продакшн. Начали юзать javascript где ни попадя (вплоть до десктопного ПО, ЛОЛ!) - вот тебе и продакшн.

Сама наколенная поделка для генерации отчетов от сисадминс ни в чем не виновата.

так я ее и не обвиняю. Ненависть и обвинение это разные вещии. Для скриптоты сисадминов есть пистон и баш, для всего остального есть другие ЯП. Perl отлично себя чувствует в однострочниках для парсинга строчек - вот там да, он просто непобедим.

reprimand ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

почему надо писать use strict и ему нет ключа как -W

юзать ключи вообще-то считается плохим тоном, пишут вот так:

use strict;
use warnings;

почему эта якобы замена sh & awk не может поддержать все операторы шелла (ну там >>, >, -nt (хотя это test, но остальные же перл поддерживает)) и не может парсить строку как awk — мне часто приходится включать куски шелл-кода, это раздражает

зачем тебе >> и >? полноценный ЯП применяют там, где скриптоты не хватает. Даже на Си (это мой основной ЯП) >> и > можно на коленке напедалить за пару минут если не быстрее.
Как именно ты хочешь парсить строку при помощи AWK?

как сделать чтобы f($a) напечатала «a=3» и $b=$a; f($b) напечатала «b=3» — на си/плюсах похожее можно сделать дефайном

не распарсил. Напиши развернутый вопрос.

у меня всегда проблема с кодировками, если я пытаюсь использовать перловый «сервис» на эту тему — и кое-кто где-то утверждал, что там это непросто (утверждал не неосилятор, а человек, предлагавший свои услуги платно)

Что за проблема с кодировками? ЕМНИП, use utf8; решало все проблемы когда я еще работал с перлом

впечатление такое, что ооп делалось на «отвяжись»; есть ли проверка количества аргументов методов? вообще проверка количества аргументов похоже единственное, что перл умеет хоть как-то проверять, да и то при ооп использовать невозможно

там не только ООП, там всё делалось отсутствием метода под названием «нагромождение». Вспоминай «базар vs собор».

где приличная документация по языку? man pages ужасны

гугел и вэбовский perldoc

почему warn печатает про номер строки и т.п., если строка заканчивается на \r ? я хочу сказать, что \r должна была бы вести себя как \n, но не ведет — это мешает сделать удобный выхлоп прогресса

омг, это в каких случаях у тебя строка заканчивается на \r? ЕМНИП бывают только \n в случае юниксов и \r\n в случае венды.

это что, скриптовый язык? у меня шаблон создания скрипта на 10 строчек (включая пустые), почти как на яве, вместо ожидаемого для скриптового языка «включил и поехал»

особенность языка. Попробуй пистон, некоторым нравится.

есть ли вариант для создания модуля, короче чем этот

этот способ создания модуля не очень корректный. Вообще, рекомендую perl best practice.

reprimand ★★★★★
()
Ответ на: комментарий от annulen

там почти в каждой строчке говорится о variable

и действительно

но я не принимал это всерьез — я считал, что это такой сокращенный способ сказать «значение переменной»

работать с переменной, а не с ее значением выглядит диковато, но этот подход я очень подробно обдумаю

www_linux_org_ru ★★★★★
() автор топика
Последнее исправление: www_linux_org_ru (всего исправлений: 2)
Ответ на: комментарий от reprimand

Perl отлично себя чувствует в однострочниках для парсинга строчек - вот там да, он просто непобедим.

Да уж, так себе ниша. И то, едва намечаются какие то структуры данных в скрипте, начинается цирк с конями. Не очень понимаю что курили люди, которые внедряли это в продакшн когда то. Ну спишем на лихие 90-е, ггг.

anonymous
()
Ответ на: комментарий от anonymous

структуры данных в скрипте

парсинга строчек

ээээм.

reprimand ★★★★★
()
Ответ на: комментарий от reprimand

омг, это в каких случаях у тебя строка заканчивается на \r?

for($i=1;$i<100;$i++) 
{ 
  print STDERR "processing $i\r";
}

print STDERR "\n\n\n";

а с warn так не выйдет

www_linux_org_ru ★★★★★
() автор топика
Ответ на: комментарий от reprimand

не распарсил. Напиши развернутый вопрос.

как сделать стрингификацию на перле? вот пример на с++:

#include <iostream>

#define say(x) do { std::cout << #x << '=' << x << '\n'; } while (0)

int main()
{
    int a=3;
    say(a); // вот тут мы обходимся без кавычек и без повторений, так же и в перле надо, чтобы было без кавычек и без повторений
    return 0;
}

зачем надо? если мы распарсили строку в переменные foo bar baz, то просто сказать say($foo, $bar, $baz), а не say(foo=>$foo, bar=>$bar, baz=>$baz)

www_linux_org_ru ★★★★★
() автор топика
Последнее исправление: www_linux_org_ru (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.