2012-11-16 64 views
6

我需要在Perl腳本中打開超過10,000個文件,因此我要求系統管理員將我的帳戶限制更改爲14,000。 ulimit -a現在顯示了這些設置:在Perl中打開超過10,000個文件的問題

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); 
} 
+3

您是否有其他進程在打開文件時運行? –

+0

'for($ i = 256; $ i> = 0; $ i - )'生成* 257 *個文件。當這個失敗時你會得到什麼輸出? – Borodin

回答

8

您可能能夠解決的限制與FileCache核心模塊(保存的文件超過了系統允許打開)。

使用的cacheout代替open,我能打開Linux的100334個文件:

#[email protected]:~/Test$ ulimit -n 
1024 

#[email protected]:~/Test$ perl plimit.pl | head 
100333 
100332 
100331 
100330 
100329 

#[email protected]:~/Test$ perl plimit.pl | tail 
test100330 
test100331 
test100332 
test100333 

#[email protected]:~/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:

#[email protected]:~/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:

#[email protected]:~/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 
+0

非常感謝您的信息。 FileCache工作。文件緩存如何工作以及如何克服操作系統限制?這是否發生在JAVA和C程序有單獨的模塊像FileCache使用許多文件句柄? – Arav

+1

@Arav - 閱讀代碼...'perldoc -m FileCache' – runrig

+1

@Arav - FileCache文檔包含它如何工作的準確描述。我不知道用於C或Java的類似模塊。 –

4

在沒有遇到您描述的錯誤的情況下,您的程序和以下更簡單的Windows程序包和Linux程序包測試過。

my @files; 
for (;;) { 
    print [email protected], "\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。

+0

非常感謝您的信息。我嘗試運行c程序,但它給我 /usr/ucb/cc:language可選軟件包未安裝 – Arav

+0

檢查gcc也未安裝。我沒有root用戶名我可以下載並使用它。我在哪裏可以找到用於solaris 10的cc編譯器。 – Arav

+0

FileCache正在工作,但我想測試c程序。 – Arav

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限制是不可原諒的,但通常有數百個打開的文件句柄表示您的程序可能設計得更好。

+0

非常感謝您的信息。 FileCache工作。文件緩存如何工作以及如何克服操作系統限制?這是否發生在JAVA和C程序有單獨的模塊像FileCache使用許多文件句柄。 – Arav

+1

是的,它會影響Solaris 10上的每個32位程序,除非它們按照文章中的說明專門編寫和編譯。這裏是[一個Java人有同樣的問題](http://stackoverflow.com/questions/1661322/too-many-open-file-handles)和[另一個](http://bugs.sun.com/bugdatabase/ view_bug.do?bug_id=6533291)。雖然看到Oracle如何擁有Solaris和Java,但我懷疑他們已經爲Java解決了這個問題......但如果他們沒有,我也不會感到驚訝。我不知道Java和C程序員如何解決它。 – Schwern

+1

C程序員通過編譯64位或通過源代碼使用[擴展FILE API](http://www.oracle.com/technetwork/server-storage/solaris10/stdio-256-136698.html)更改或LD_PRELOAD選項。 – alanc

0

您有256個文件的限制。你忘了STDIN,STDOUT和STDERR。您的253 +默認值3 = 256.