2012-11-16 20 views
6

Potrzebuję otworzyć ponad 10 000 plików w skrypcie Perla, więc poprosiłem administratora systemu o zmianę limitu na moim koncie na 14 000. ulimit -a pokazuje teraz te ustawienia:Problemy z otwarciem ponad 10 000 plików w Perlu

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 

Po zmianie wpadłem testowy Perl program, który otwiera/256 tworzy pliki i zamyka 256 uchwyty plików na końcu skryptu. Kiedy tworzy 253 plików, program umiera mówiąc zbyt wiele otwartych plików. Nie rozumiem, dlaczego dostaję tego błędu.

Pracuję na platformie Solaris 10. To jest mój kod

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

Czy masz inny proces z uruchomionymi plikami? –

+0

'for ($ i = 256; $ i> = 0; $ i -)' tworzy pliki * 257 *. Jakie wyniki uzyskujesz, gdy to się nie powiedzie? – Borodin

Odpowiedz

8

może być w stanie obejść ograniczenia z modułem jądra FileCache (zachować więcej plików otwarty niż pozwoleniu systemu).

Korzystanie cacheout zamiast open, byłem w stanie otworzyć 100334 plików w systemie Linux:

#[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 


zmodyfikowana wersja skryptu (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); 
} 

aktualizacja

FileCache automatycznie zamyka i ponownie otwiera pliki jeśli przekroczy maksymalną liczbę Twojego systemu deskryptorów pliku lub sugerowany maksymalny maxopen (nofile zdefiniowany w sys/param.h).

W moim przypadku na polu linux, to 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 

Używanie lsof (lista otwartych plików) polecenie, zmodyfikowana wersja skryptu otwarty na większość 260 100334 plików:

#[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

Wielkie dzięki za informacje. FileCache działał. Jak działa filecache i jak jest on w stanie pokonać ograniczenia OS? Czy tak się dzieje w przypadku programów JAVA i C z oddzielnym modułem, takim jak FileCache, aby używać wielu uchwytów plików? – Arav

+1

@Arav - Przeczytaj kod ... 'perldoc -m FileCache' – runrig

+1

@Arav - Dokumentacja FileCache zawiera dokładny opis działania. Nie znam podobnego modułu dla C lub Java. –

4

Testowany przy użyciu zarówno programu, jak i następującego po nim prostszego programu na pudełku systemu Windows i Linuxa bez napotkania opisywanego błędu.

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

wyjściowa:

1 
2 
... 
498 
499 
500 

Nie sądzę, że to ograniczenie Perl, ale to ograniczenie systemu.

Należy zauważyć, że nie powiedzie się, gdy próbujesz otworzyć 257. uchwyt procesu (STDIN + STDOUT + STDERR + 253 = 256), co prowadzi mnie do przekonania, że ​​liczba otwartych uchwytów pliku, które proces musi mieć, musi zmieścić się w 8 bitach na Twój system. Możesz spróbować zweryfikować to, pisząc odpowiedni program C i uruchamiając go na tym samym komputerze.

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

Aktualizacja: Zostało to potwierdzone here. Dzięki, Schwern.

+0

Wielkie dzięki za informacje. Próbowałem uruchomić program c, ale to daje mi opcjonalny pakiet językowy /usr/ucb/cc: nie zainstalowany – Arav

+0

Sprawdzony pod kątem gcc również nie jest zainstalowany. Nie mam identyfikatora użytkownika root, mogę go pobrać i używać. gdzie mogę znaleźć kompilator cc dla Solaris 10. – Arav

+0

FileCache działa, ale chciałbym przetestować program c. – Arav

16

According to this article jest to domyślne ograniczenie 32-bitowego systemu Solaris. Program jest zwykle ograniczony do używania pierwszych 256 numerów plików. STDIN, STDOUT i STDERR zajmują 0, 1 i 2, co daje 253. Nie jest to prosty proces dookoła, ulimit tego nie zrobi, i nie wiem, czy Perl to uszanuje.

Here's a discussion about it on Perlmonks z kilkoma sugerowanymi obejściami pracy, takimi jak FileCache.

Ograniczenie systemu Solaris jest niewybaczalne, ale posiadanie setek otwartych uchwytów plików wskazuje, że program mógł być lepiej zaprojektowany.

+0

Wielkie dzięki za informacje. FileCache działał. Jak działa filecache i jak jest on w stanie pokonać ograniczenia OS? Czy tak się dzieje, ponieważ programy JAVA i C mają oddzielny moduł, taki jak FileCache, aby używać wielu uchwytów plików. – Arav

+1

Tak, powoduje to każdy 32-bitowy program w systemie Solaris 10, o ile nie zostały one specjalnie napisane i skompilowane w sposób opisany w artykule. Oto [osoba Java z tego samego problemu] (http://stackoverflow.com/questions/1661322/too-many-open-file-handles) i [inny] (http://bugs.sun.com/bugdatabase/ view_bug.do?bug_id=6533291). Chociaż patrząc na to, jak Oracle posiada zarówno system Solaris, jak i Java, podejrzewam, że pracowali nad tym w Javie ... ale nie byłbym zbyt zaskoczony, gdyby tego nie robili. Nie wiem, co robią programiści Java i C, aby to obejść. – Schwern

+1

C programiści obejść albo przez kompilację 64 lub za pomocą rozszerzonej [PLIK] API (http://www.oracle.com/technetwork/server-storage/solaris10/stdio-256-136698.html) albo przez źródło zmiany lub opcje LD_PRELOAD. – alanc

0

masz limit 256 plików. Zapomniałeś o STDIN, STDOUT i STDERR. Twój 253 + domyślny 3 = 256.