Не для кого не секрет, что Perl любит кушать память и при написании кода нужно обращать внимание на всякие мелочи, если вы работаете с большими объемами данных. Проблема заключается в том, что когда Perl съедает память, он ее не возвращает системе, а оставляет себе для повторного использования. Для долгоживущих процессов это иногда создает проблемы.
Допустим у нас есть огромный блок данных - $data;
и функция для записи данных в файл $file - set_file_content;
sub set_file_content {
my ($file, $data) = @_;
....
print FILE $data;
}
Вариант 1
set_file_content("$file", "$data") - самый нерациональный вариант вызова. Параметры заключены в двойные кавычки и Perl создаст в памяти еще одну копию строки для передачи в функцию.
Вариант 2
set_file_content($file, $data) - хороший вариант вызова, но тут уже проблема возникает в самой функции set_file_content - она внутри когда принимает параметры, копирует их в локальные переменные.
Вариант 3
Следовательно нужно избежать копирования данных внутри функции set_file_content и многие решат передавать и принимать данные по ссылке
используя токой вот вызов: set_file_content($file, \$data)
и такую реализацию функции:
sub set_file_content {
my ($file, $data_ref) = @_;
....
print FILE $$data_ref;
}
По использованию памяти - это отличный вариант, но есть другие недостатки:
1. Первый параметр передается обычным способом, второй по ссылке
2. Если код уже написан, то необходимо изменить везде код вызова функции
3. Самый существенный для меня недостаток - когда я передаю параметр по ссылке, я всегда задумываюсь, а не проделает ли функция каких либо операций с $data внутри и можно будет ли использовать переменную $data после вызова функции.
Вариант 4 (Сабж)
Так вот собственно перейдем к сабжу: прием по ссылке
Функцию set_file_content реализовываем следующим образом:
sub set_file_content {
my ($file, $data_ref) = ($_[0], \$_[1]);
....
print FILE $$data_ref;
}
Вызов мы используем обычный - set_file_content($file, $data);
В результате мы получаем полностью аналогичное потребление памяти как и с вариантом передачи по ссылке, но лишенный всех недостатков.
Почему это работает?
В перле есть понятие ссылки, а есть понятие алиаса(второго имени). Так вот, в массиве @_ содержатся алиасы на переданные параметры и модифицируя элементы @_, мы модифицируем внешние переменные.
Алиасы также используются в map, grep, foreach
Например:
foreach my $var (@array) {
$var = 1;
}
мы присвоим "1" каждому элементу массива @array
ЗЫ:
Когда использовать прием по ссылке, а когда передачу по ссылке? я придерживаюсь следующего правила:
some_function(\$data); - функция изменяет $data внутри
some_function($data); - функция не изменяет $data внутри
воскресенье, 21 марта 2010 г.
Подписаться на:
Комментарии к сообщению (Atom)
4 коммент.:
>я всегда задумываюсь, а не проделает ли функция каких либо операций с $data внутри
Но ведь и в 4-ом варианте функция может проделать какие-либо операции с $data.
P.S. Не могу авторизоваться по OpenID LJ. "Не удалось проверить учетные данные OpenID." и все тут.
Естественно может, но это уже явное зло - менять переменную, когда ее передали не как ссылку:). Было бы очень печально, если бы изменение переменной, которую передали не по ссылке было бы нормальной практикой программирования.
То есть, когда я вижу get_file_content($file, $data), то я считаю, что get_file_content точно внутри ничего не сделает лишь потому, что это не есть нормально - я ж не передавал ссылку на переменную... и если функция все-таки что-то делает внутри с $data - это плохой стиль программирования
ЗЫ: По поводу OpenID LJ - у меня все заработало.
Делал так:
1. Зашел в свой аккаунт в LJ
2. В этом блоге выбрал использовать LiveJournal и указал имя пользователя LJ
3. При попытке опубликовать сообщение, меня перебросило на LJ на "Подтверждение идентификации" для http://www.blogger.com.
4. После подтверждения могу использовать аккаунт LJ для комментирования
В 4-ом варианте функция также может проделать какие-либо операции с $data
2Игорь: да, все верно
Отправить комментарий
Не забудьте добавить себя в постоянные читатели и включить уведомления о новых комментариях, либо воспользуйтесь RSS каналом ;)