Perl - ошибка слишком большого количества файлов при использовании Oracle DBD - PullRequest
2 голосов
/ 22 июня 2010

Может кто-нибудь посоветовать, почему я получаю ошибки при открытии файла в коде ниже.Ошибки начинаются примерно на полпути 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;
}

Ответы [ 2 ]

5 голосов
/ 22 июня 2010

Вам необходимо использовать:

use warnings;
use strict;

Это скажет вам, что вы используете глобальные переменные $ i и $ j в подпрограмме. Так как у вас есть несколько потоков, обращающихся к переменным, все чертовы рвутся. Кроме того, все они тоже используют один файл - еще один источник проблем. И вы поняли, что у вас есть и скалярный '$ threads', и массив '@threads'?

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

Избегайте использования формы ФАЙЛОВ 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.

1 голос
/ 22 июня 2010

Попробуйте

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...