我需要在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);
}
答案 0 :(得分:16)
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限制是不可原谅的,但通常有数百个打开的文件句柄表明您的程序可以更好地设计。
答案 1 :(得分:8)
您可以使用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);
}
<强>更新强>
如果超出系统的最大文件描述符数或建议的最大maxopen(在sys / param.h中定义的NOFILE), FileCache
会自动关闭并重新打开文件。
就我而言,在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(列表打开文件)命令,脚本的修改版本最多可打开100个文件中的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
答案 2 :(得分: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;
}
更新:已经确认here。谢谢,Schwern。
答案 3 :(得分:0)
你有256个文件的限制。你忘记了STDIN,STDOUT和STDERR。你的253 +默认3 = 256。