[Moscow.pm] Ограничить время выполнения произвольной функции

Андрей Костенко andrey на kostenko.name
Пт Янв 29 04:22:16 PST 2010


если выполняется очень тяжелая логика, то я делал fork/wait + alarm

2010/1/29 Dmitry E. Oboukhov <unera на debian.org>:
> стоит сабжевая задача.
>
> Для ее решения я пошел по пути описанному в perldoc -f alarm (на CPAN
> есть штук пяток модулей на эту тему например Sys::AlarmCall (он же
> рекомендован к употреблению в perlfaq), я про них знаю, но описанная
> здесь проблема в них во всех проявляется, потому стоит задача
> написания нового модуля, либо прийти к нереализуемости задачи), итак,
> в perldoc -f alarm пример:
>
>   eval {
>       local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
>       alarm $timeout;
>       $nread = sysread SOCKET, $buffer, $size;
>       alarm 0;
>   };
>   if ($@) {
>       die unless $@ eq "alarm\n";   # propagate unexpected errors
>       # timed out
>   }
>   else {
>       # didn't
>   }
>
>
> пишем вместо sysread ту функцию, которую хотим ограничить по времени
> работы и вуаля - работает. Если посмотреть CPAN'овские модули, то все
> они работают на этой технологии, только дополнительно делают следующие
> вещи:
>    - определяют контекст вызова wantarray
>    - запоминают/восстанавливают предыдущее значение alarm
>    - ловят исключения в самой функции
>    - прочий сервисный шняг
> но это несущественно, собственно вернемся к проблеме.
>
> допустим мы заменили sysread на foo()
>
> и как оказывается работа сей конструкции зависит от того чтоже там
> внутри foo()
>
> допустим foo у нас содержит такой код:
>
> sub foo
> {
>    for ($i = 0; $i < 100; $i++) {
>        sleep 1;
>    }
> }
>
> с такой функцией будет все ок.
>
> но вот если например внутри функции хотя бы в одном месте будет eval
> sub foo
> {
>    for ($i = 0; $i < 100; $i++) {
>        eval "sleep 1";
>    }
> }
>
> то именно этот eval и получит die "alarm\n".
> Теперь все зависит от функции, распространит она die выше или не
> распространит. можно было бы сказать что функция которая не
> распространяет die - "неправильная", да только таких функций в
> cpan-модулях чуть меньше чем дохрена, да и "правильные есть"
>
> sub divide($$)
> {
>    my ($a, $b) = @_;
>    die "на ноль делить нельзя" unless $b;
>    return $a / $b;
> }
>
> тот кто использует divide знает что исключение может быть выброшено
> строго в одном случае и может его просто поймать и не распространить
> дальше, а скажем изменить алгоритм основной работы итп.
>
> Получается хоть функция приведенная в perldoc -f alarm SIGALRM и
> словила, но тормознуть выполнение "подопытной" функции не может, если
> тот содержит eval.
>
> Искал искал решение, но пока ничего приемлемого не нашел.
> Может кто боролся с подобной проблемой? есть какие-либо предложения?
>
> в обработчике SIGALRM мы в принципе видим стек вызовов, можно ли
> как-то из него изъять несколько уровней? perl'овыми средствами
>
> --
> ... mpd is off
>
> . ''`.                               Dmitry E. Oboukhov
> : :’  :   email: unera на debian.org jabber://UNera@uvw.ru
> `. `~’              GPGKey: 1024D / F8E26537 2006-11-21
>  `- 1B23 D4F8 8EC0 D902 0555  E438 AB8C 00CF F8E2 6537
>
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.10 (GNU/Linux)
>
> iEYEAREDAAYFAktisyEACgkQq4wAz/jiZTdEEACgumiLhm31+IWlasr2HDEvOdy1
> pjkAoKODwg5xIwcwIALTe6JLrbzY3zYo
> =vnbh
> -----END PGP SIGNATURE-----
>
> --
> Moscow.pm mailing list
> moscow-pm на pm.org | http://moscow.pm.org
>
>


Подробная информация о списке рассылки Moscow-pm