Perl — слишком много файлов при использовании DBD Oracle

Может кто-нибудь посоветовать, почему я получаю ошибки при открытии файла в приведенном ниже коде. Ошибки начинаются примерно на полпути через 9-ю итерацию из 25 потоков и представляют собой ошибки «Слишком много открытых файлов». Ошибка возникает только при работе в потоках и только при использовании подключения/отключения DBI. Это вообще не должно влиять на количество открытых файлов, не так ли? Я новичок в Perl, поэтому не уверен, что сделал что-то странное. Это на Perl 5.8.8. на Солярис 10.

use threads ();
use DBI;
use DBD::Oracle;

my $thrds=25;
my $iter=10;
my @threads;

for (my $j=0; $j<$iter; $j++) {
    &start($j);
}

sub start {
    my $k=$_[0];
    for (my $i=0; $i<$thrds; $i++) {
        $threads[$i] = threads->new(\&RunThread,$k, $i);
    }
    for (my $i=0; $i<$thrds; $i++) { $threads[$i]->join; }
}

sub RunThread {
    my $dbh = DBI->connect("dbi:Oracle:lnrmsd9.world", "rms_reader", "rms_reader") or die "failed connect";
    my ($x, $y)=@_;
    open (my $fh, ">/tmp/da") or die "failed $! at iter $x thread $y";
    close ($fh);
    $dbh->disconnect;
}

person Joe Watkins    schedule 22.06.2010    source источник
comment
Маленькая бинарная иконка в редакторе предназначена для вставки кода. (См. справочное руководство по разметке.)   -  person Ether    schedule 22.06.2010
comment
Я использовал это, и это не сработало по какой-то причине. Во всяком случае, теперь хорошо, спасибо   -  person Joe Watkins    schedule 23.06.2010


Ответы (2)


Вам нужно использовать:

use warnings;
use strict;

Они сообщат вам, что вы используете глобальные переменные $i и $j в подпрограмме. Поскольку у вас есть несколько потоков, обращающихся к переменным, все рушится. Кроме того, все они используют один и тот же ФАЙЛ — еще один источник проблем. А вы знали, что у вас есть и скалярная '$threads', и массивная '@threads'?

С потоками глобальные переменные являются... ну, если не врагами, то крайне проблематичными.

Избегайте формы дескриптора FILE open; используйте my гораздо шире.

И вам не нужно говорить "используйте DBD::Oracle"; Когда-либо. Иногда вам может понадобиться использовать вариант:

use DBD::Oracle qw( :ora_types );

для получения доступа к типам данных, специфичным для Oracle.


Непроверенная версия:

use strict;
use warnings;
use threads ();
use DBI;
use DBD::Oracle;

my $threads=25;
my $iter=10;

for ($j = 0; $j < $iter; $j++) {
    &start($j);
}

sub start {
    my($j) = @_;
    my(@threads);
    for (my $i = 0; $i < $threads; $i++) {
        $threads[$i] = threads->new(\&RunThread,$j, $i);
    }
    for ($i=0; $i < $threads; $i++) { $threads[$i]->join; }
}

sub RunThread {
    my $dbh = DBI->connect("dbi:Oracle:ora", "user", "pass") or die "failed connect";
    my($j, $i) = @_;
    open(my $fh, ">/tmp/da") or die "failed $! at iter $j thread $i";
    close $fh;
    $dbh->disconnect;
}

Одного я не понял - почему бы мне не использовать use DBD::Oracle;?

Если вы посмотрите на 'perldoc DBD::Oracle', вы увидите синопсис:

use DBI;

$dbh = DBI->connect("dbi:Oracle:$dbname", $user, $passwd);

Итак, первичная документация по модулю DBD::Oracle показывает, что вы не используете его напрямую.

При его использовании нет никакого вреда; нет необходимости использовать его. Модуль DBI автоматически загружает драйвер, указанный в строке подключения в вызове DBI->connect(). Написав use DBD::Oracle;, вы избавите DBI от необходимости фактически выполнять загрузку (это уже сделано). Я полагаю, вы также заставите Perl убедиться, что модуль доступен для загрузки с предложением use.

person Jonathan Leffler    schedule 22.06.2010
comment
+1. Perl — один из самых простых языков, с помощью которого можно выстрелить себе в ногу: существует так много способов выстрелить себе в ногу, что вы отправляете запрос на comp.lang.perl.misc, чтобы определить оптимальный подход. После просеивания 500 ответов (что вы выполняете с помощью короткого скрипта Perl) вы ставите перед собой задачу просто и элегантно выстрелить себе в ногу, пока не обнаружите, что, хотя в большинстве случаев это работает нормально, Windows, VMS и различные Разновидности Linux позволят вам выстрелить вам в ногу раньше, чем ваш Perl-скрипт. ;-) - person DCookie; 22.06.2010
comment
Perl также предоставляет отличные средства диагностики для устранения прострелов стопы — если программист решит их использовать. - person Ether; 22.06.2010
comment
Хорошо, спасибо, это было немного грязно! Мое оправдание в том, что быстро и грязно воссоздавать проблему в более крупном сценарии. В любом случае, я прибрался (и изменил код в исходном сообщении), но, к сожалению, я все еще получаю ошибку «Слишком много открытых файлов» после 9 итераций. Так что проблема еще не решена. Одного я не понял - почему бы мне не использовать use DBD::Oracle; ? - person Joe Watkins; 23.06.2010
comment
@Joe Watkins: см. конец ответа на вопрос «почему бы не использовать DBD::Oracle». О просочившихся файловых дескрипторах: начинают глючить. Одна проверка пропущена: успешно ли закрываются? Если нет, то это где вы утечки. В противном случае мне кажется, что утечка должна быть в DBI и DBD:: Oracle - похоже, что $dbh->disconnect не выпускает дескриптор файла. Еще один элемент, который необходимо проверить, — это DBD::Oracle, скомпилированный с потокобезопасной библиотекой OCI и знающий, что будут использоваться потоки. Если у вас есть утечка дескриптора, сообщите об этом в список рассылки поддержки [email protected]. - person Jonathan Leffler; 23.06.2010
comment
@Joe Watkins: см. также веб-сайт DBI. При сообщении о проблемах вам необходимо указать версии DBI и DBD::Oracle, а также версию Oracle (клиентское программное обеспечение — OCI). И, если вы используете архаичный код, ожидайте, что первым ответом будет «обновить до текущей версии». - person Jonathan Leffler; 23.06.2010

Пытаться

my $FILE;
open ($FILE, ">/tmp/da") or die "failed $! at iter $j thread $i";
close ($FILE);

Это лучшая практика.

person J-16 SDiZ    schedule 22.06.2010