Никогда до этого не использовал треды(threads) в Perl - как-то не доверял я им и использовал forkи... и как оказалось не зря!
И настал тот день, когда от тредов никуда не убежишь(на самом деле убежишь, но про это дальше) - нужно было включить многопоточность для модуля Fuse.pm(просто передается дополнительный параметр threaded => 1), и тогда на каждый вызов файлофай системы будет создаваться тред.
Собственно сабж:
- Переменные по-умолчанию не являются общими между тредами. Это означает, что каждый раз когда вы стартуете тред, все структуры данных копируются в новый тред. Все - это значит все, включая внутренности всех пакетов, глобальные переменные, лексические...
- Общие переменные на самом деле - не общие, а просто связанные(Tied), со всеми вытекающими последствиями - требуют больше памяти и более медленные. Подробней тут http://www.perlmonks.org/index.pl?node_id=288022
- Самое печальное. Треды ЛИКАЮТ!!! Каждый запущенный тред после своего завершения не возвращает часть памяти!!!
- Треды в Perl требуют больше памяти чем fork-и !!! Да именно так :), поскольку fork-и используют COPY-ON-WRITE при копировании процесса в памяти.
- Нужен Perl скомпилированный с поддержкой тредов.
Достаточно запустить и понаблюдать за потреблением памяти процессом.
use threads;
while (1) {
threads->create(sub{})->join();
}
Решение.
Использовать fork-и :) (естественно там, где они нативно поддерживаются). По существу:Решение.
- Fork-и не ликают
- Fork-и понятней и не подвержены ошибкам связанными с семафорами и локами данных.
- Сейчас в большинстве unix системах fork-и - дешевые(в Linux в том числе), поскольку используется COPY-ON-WRITE метод. То есть, при создании нового процесса содержимое памяти не копируется. Накладные расходы только на организацию нового процесса.
- Работают на любой версии Perl
Представьте себе, что есть код написанный с использованием тредов, просто напишите вначале кода use forks; и код будет использовать fork-и вместо тредов ( с Fuse.pm работает ).
Вот пример( и код перестает ликать):
use forks;
use threads;
while (1) {
threads->create(sub{})->join();
}
8 коммент.:
что за слово ЛИКАТЬ...
Пиши либо по английски: "memory leak", либо по-русски: "утечка памяти"
привычка... сленг... надеюсь, что в этот раз все поймут :)
Полностью согласен, что лучше писать "утечка памяти" либо "memory leak"
Спасибо за подсказку по поводу forks. Однажды пытался устранить утечку памяти в скрипте, использующем threads, пытался отловить её различными утилитами типа Devel::Leak, Devel::LeakTrace, но ничего не получилось и я забросил это дело.
То, что "текут" сами треды - не было даже мысли.
К первому комментарию.
А мне нравится слово ЛИКАТЬ!!! Я буду его использовать на ровне с глаголами ГУГЛИТЬ, ПРОГАТЬ и ХАКНУТЬ.
Нашелся тут учитель русского языка и литературы. Слово "ЛИКАТЬ" ему не подуше :)
Как ты себе это представляешь:
"Треды утечка памяти"? Или "Треды утекают памятью"? Или "Треды memory leak"? Фигня какая-то.
А по теме. Молодец, Курец. Давай по больше таких постов. Хотелось бы услышать в каких случаях стоит использовать треды (не зря же их придумали). :)
Может треды придумали для эмуляции fork-ов под виндой( "The initial impetus for implementing ithreads was to emulate fork for Microsoft systems" - цитата с Camel book ) ;)... ну и на маленьких по размеру процессах(до 15 мб) треды были бы неплохи если бы не ликали.
Небольшой тест:
Файл test.pl
use threads;
my $test = 'x' x (15*1024**2);
for (1..1_000) {
threads->create(sub{})->join();
}
time perl test.pl
real 0m12.139s
user 0m12.029s
sys 0m0.101s
time perl -Mforks test.pl
real 0m10.450s
user 0m6.157s
sys 0m5.666s
Есть еще разница при работе с общей памятью процесса и прогоном данных через пайп... но нужно смотреть конкретные примеры.
Естественно в fork-ах можно также использовать общий пул данных. Есть много модулей для этого, например - IPC::ShareLite ...
Главное что решение простое и легкое, просто новый use добавить, красиво
2 Антон
У Трэдов наблюдается утечка памяти :)
Спасибо за наводку на модуль fork!
http://laziness-impatience-hubris.blogspot.com/2009/12/threads.html
К сожелению в данном модуле нехватает функционала. Например неработают модули:
http://search.cpan.org/~tag/POE-Component-Pool-DBI-0.014/
http://search.cpan.org/~tag/POE-Component-Pool-Thread-0.015/
Хотя POE-Component-Pool-Thread-0.015 это совсем другая парадигма ...
Отправить комментарий
Не забудьте добавить себя в постоянные читатели и включить уведомления о новых комментариях, либо воспользуйтесь RSS каналом ;)