【问题标题】:Problems opening more than 10,000 files in Perl在 Perl 中打开超过 10,000 个文件时出现问题
【发布时间】:2012-11-04 17:34:57
【问题描述】:

我需要在 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

更改后,我运行了一个测试 Perl 程序,该程序打开/创建 256 个文件并在脚本末尾关闭 256 个文件句柄。当它创建 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);
}

【问题讨论】:

  • 您是否有另一个进程正在运行并打开文件?
  • for ($i = 256; $i >= 0; $i--) 制作 257 个文件。失败时你会得到什么输出?

标签: perl file solaris ulimit


【解决方案1】:

According to this article 这是 32 位 Solaris 的默认限制。程序通常仅限于使用前 256 个文件编号。 STDIN、STDOUT 和 STDERR 取 0、1 和 2,剩下 253。解决它不是一个简单的过程,ulimit 不会这样做,我不知道 Perl 是否会尊重它。

Here's a discussion about it on Perlmonks 以及一些建议的解决方法,例如 FileCache

虽然 Solaris 的限制是不可原谅的,但通常有数百个打开的文件句柄表明您的程序可以设计得更好。

【讨论】:

  • 非常感谢您提供的信息。文件缓存工作。文件缓存如何工作以及如何克服操作系统限制?对于 JAVA 和 C 程序是否会发生这种情况,它们具有像 FileCache 这样的单独模块来使用许多文件句柄。
  • 是的,它会影响 Solaris 10 上的每个 32 位程序,除非它们是按照文章中的说明专门编写和编译的。这是a Java person with the same problemanother。虽然看到 Oracle 如何同时拥有 Solaris 和 Java,但我怀疑他们已经为 Java 解决了这个问题……但如果他们没有,我不会太惊讶。我不知道 Java 和 C 程序员如何解决这个问题。
  • C 程序员通过编译 64 位或通过源代码更改或 LD_PRELOAD 选项使用 extended FILE api 来解决它。
【解决方案2】:

您也许可以使用 FileCache 核心模块解决限制(保持打开的文件数量超过系统允许的数量)。

使用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(列出打开的文件)命令,修改后的脚本版本最多打开 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

【讨论】:

  • 非常感谢您提供的信息。文件缓存工作。文件缓存如何工作以及如何克服操作系统限制? JAVA 和 C 程序有像 FileCache 这样的单独模块来使用许多文件句柄时会发生这种情况吗?
  • @Arav - FileCache 文档包含对其工作原理的准确描述。我不知道用于 C 或 Java 的类似模块。
【解决方案3】:

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

更新:已确认here。谢谢,施韦恩。

【讨论】:

  • 非常感谢您提供的信息。我尝试运行 c 程序,但它给了我 /usr/ucb/cc: 未安装语言可选软件包
  • 检查了 gcc 也没有安装。我没有root用户ID,我可以下载并使用它。我在哪里可以找到 solaris 10 的 cc 编译器。
【解决方案4】:

您有 256 个文件的限制。您忘记了 STDIN、STDOUT 和 STDERR。你的 253 + 默认 3 = 256。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-04
    • 1970-01-01
    • 2011-09-02
    • 2019-01-22
    • 2010-10-12
    • 2017-08-27
    • 2019-09-14
    • 2020-03-10
    相关资源
    最近更新 更多