7

Perl スクリプトで 10,000 を超えるファイルを開く必要があるため、システム管理者にアカウントの制限を 14,000 に変更するよう依頼しました。ulimit -a次の設定が表示されます。

core file size        (blocks, -c) unlimited
data seg size         (kbytes, -d) unlimited
file size             (blocks, -f) unlimited
open files                    (-n) 14000
pipe size          (512 bytes, -p) 10
stack size            (kbytes, -s) 8192
cpu time             (seconds, -t) unlimited
max user processes            (-u) 29995
virtual memory        (kbytes, -v) unlimited

変更後、256 個のファイルを開いたり作成したり、スクリプトの最後で 256 個のファイル ハンドルを閉じたりするテスト Perl プログラムを実行しました。253 個のファイルを作成すると、開いているファイルが多すぎると言ってプログラムが終了します。このエラーが発生する理由がわかりません。

Solaris 10 プラットフォームで作業しています。これは私のコードです

my @list;
my $filename = "test";

for ($i = 256; $i >= 0; $i--) {
    print "$i " . "\n";
    $filename = "test" . "$i";
    if (open my $in, ">", ${filename}) {
        push @list, $in;
        print $in $filename . "\n";
    }
    else {
        warn "Could not open file '$filename'. $!";
        die;
    }
}

for ($i = 256; $i >= 0; $i--) {
    my $retVal = pop @list;
    print $retVal . "\n";
    close($retVal);
}
4

4 に答える 4

16

この記事によると、これは 32 ビット Solaris のデフォルトの制限です。プログラムは通常、最初の 256 ファイル番号の使用に制限されています。STDIN、STDOUT、および STDERR は 0、1、および 2 を取るため、253 が残ります。これを回避するのは単純なプロセスではありません。ulimit はそれを行いません。Perl がそれを尊重するかどうかもわかりません。

ここでは、Perlmonks に関する議論があり、 FileCacheなどのいくつかの回避策が提案されています。

Solaris の制限は許されませんが、一般に、何百もの開いているファイルハンドルがあるということは、プログラムをより適切に設計できることを示しています。

于 2012-11-16T02:17:47.290 に答える
8

FileCache Coreモジュールで制限を回避できる場合があります(システムが許可するよりも多くのファイルを開いたままにします)。

cacheoutの代わりにを使用しopenて、Linuxで100334ファイルを開くことができました。

#david@:~/Test$ ulimit -n
1024

#david@:~/Test$ perl plimit.pl | head
100333 
100332 
100331 
100330 
100329 

#david@:~/Test$ perl plimit.pl | tail
test100330
test100331
test100332
test100333

#david@:~/Test$ ls test* | wc -l
100334


スクリプトの修正バージョン(plimit.pl)

my @list;

use FileCache;

$mfile=100333;

my $filename="test";
for($i = $mfile; $i >= 0; $i--) {
    print "$i " . "\n" ;
    $filename = "test" . "$i";
    #if (open my $in, ">", ${filename}) {
     if ($in = cacheout( ">", ${filename}) ) {
        push @list,$in;
        print $in  $filename . "\n";
    } else {
        warn "Could not open file '$filename'. $!";
        die;
    }
}
for($i = $mfile; $i >= 0; $i--) {
    my $retVal = pop @list;
    print $retVal . "\n";
    close($retVal);
}

アップデート

FileCacheシステムのファイル記述子の最大数、または推奨される最大maxopen(sys / param.hで定義されているNOFILE)を超えると、ファイルを自動的に閉じて再度開きます。

私の場合、Linuxボックスでは256です。

#david@:~/Test$ grep -B 3 NOFILE /usr/include/sys/param.h 

/* The following are not really correct but it is a value 
   we used for a long time and which seems to be usable.  
   People should not use NOFILE and NCARGS anyway.  */
#define NOFILE      256

lsof (list open files)コマンドを使用して、スクリプトの変更バージョンは、100334ファイルのうち最大260ファイルを開きました。

#david@:~/Test$ bash count_of_plimit.sh
20:41:27 18
new max is 18
20:41:28 196
new max is 196
20:41:29 260
new max is 260
20:41:30 218
20:41:31 258
20:41:32 248
20:41:33 193
max count was 260


count_of_plimit.sh

 #!/bin/bash
 # count open files with lsof
 #
 # latest revision: 
 #   ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/
 # latest FAQ: 
 #  ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ

 perl plimit.pl > out.txt &
 pid=$!

##adapted from http://stackoverflow.com/a/1661498
HOW_MANY=0
MAX=0
while [ -r "/proc/${pid}" ]; 
do
    HOW_MANY=`lsof -p ${pid} | wc -l`
    #output for live monitoring
    echo `date +%H:%M:%S` $HOW_MANY
    # look for max value
    if [ $MAX -lt $HOW_MANY ]; then
        let MAX=$HOW_MANY
        echo new max is $MAX
    fi 
    # test every second
    sleep 1
done
echo max count was $MAX
于 2012-11-16T01:59:06.183 に答える
4

あなたが説明したエラーが発生することなく、WindowsボックスとLinuxボックスであなたのプログラムと次のより単純なプログラムの両方でテストされました。

my @files;
for (;;) {
   print 1+@files, "\n";
   open my $fh, '<', $0 or die $!;
   push @files, $fh;
   last if @files == 500;
}

出力:

1
2
...
498
499
500

これは Perl の制限ではなく、システムの制限だと思います。

プロセスの257番目のハンドル(STDIN + STDOUT + STDERR + 253 = 256)を開こうとすると失敗することに注意してください。これにより、プロセスが持つことができる開いているファイルハンドルの数は、システムの8ビットに収まる必要があると思います。これを確認するには、同等の C プログラムを作成し、同じマシンで実行します。

#include <stdio.h>
#include <stdlib.h>

int main() {
   int i = 0;
   for (;;) {
      ++i;
      printf("%d\n", i);
      if (fopen("/bin/sh", "r") == NULL) {
         perror("fopen");
         exit(1);
      }

      if (i == 500)
         break;
   }

   return 0;
}

更新: これはここで確認されました。ありがとう、シュヴェルン。

于 2012-11-16T02:00:42.570 に答える
0

256 ファイルの制限があります。STDIN、STDOUT、STDERR を忘れていました。あなたの 253 + デフォルト 3 = 256.

于 2013-10-23T08:54:22.520 に答える