Perl - 使用 DBD Oracle 时出现文件过多错误

发布于 2024-09-06 18:07:29 字数 837 浏览 10 评论 0原文

有人可以告诉我为什么在下面的代码中打开文件时出错。这些错误大约在 25 个线程的第 9 次迭代进行到一半时开始出现,并且是“打开文件过多”错误。该错误仅在线程中运行时发生,并且仅在使用 DBI 连接/断开连接时发生。这根本不会影响打开文件计数,不是吗? 我对 Perl 相当陌生,所以不确定我是否做了一些奇怪的事情。这是 Perl 5.8.8 上的。在 Solaris 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;
}

Can someone advise on why I get errors opening the file in the code below. The errors start about half way through the 9th iteration of 25 threads, and are "Too many open files" errors. The error only happens when running in threads, and only when the DBI connect/disconnect are used. This shouldn't affect the open file count at all should it?
I'm fairly new to Perl so not sure if I've done something weird. This is on Perl 5.8.8. on Solaris 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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

执妄 2024-09-13 18:07:29

您需要使用:

use warnings;
use strict;

这些会告诉您正在子例程中使用全局变量 $i 和 $j 。由于您有多个线程访问变量,所以一切都变得混乱了。此外,它们也都共享一个文件——这是另一个麻烦来源。您是否意识到您同时拥有标量“$threads”和数组“@threads”?

对于线程来说,全局变量……好吧,即使不完全是敌人,也是非常有问题的。

避免使用 open 的 FILE 句柄形式;更自由地使用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 子句加载。

You need to use:

use warnings;
use strict;

These would tell you that you're using global variables $i and $j in the subroutine. Since you've got multiple threads accessing the variables, all hell breaks loose. Also, they're all sharing a single FILE, too - another source of trouble. And did you realize you had both a scalar '$threads' and an array '@threads'?

With threads, global variables are ... well, if not exactly the enemy, extremely problematic.

Avoid the FILE handle form of open; use my much more liberally.

And you don't need to say 'use DBD::Oracle;' ever. You might sometimes need to use the variant:

use DBD::Oracle qw( :ora_types );

to gain access to Oracle-specific data types.


Untested revision:

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;
}

One thing I didn't understand - why shouldn't I use use DBD::Oracle;?

If you look at the 'perldoc DBD::Oracle', you will see the Synopsis:

use DBI;

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

So, the primary documentation for the DBD::Oracle module shows that you do not use it directly.

There is no harm done in using it; there is no need to use it. The DBI module automatically loads the driver implied by the connection string in the call to DBI->connect(). By writing use DBD::Oracle;, you save the DBI from having to actually do the loading (it is already done). I suppose you also get Perl to verify that the module is available to be loaded with the use clause.

泪意 2024-09-13 18:07:29

尝试

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

这是最佳实践。

Try

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

This is in the best practice.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文