Newsgroup: it.comp.lang.c++
Titolo: efficenza in copia files

Sto cercando di imparare a programmare in C++, avendo comunque una certa
esperienza in C.
Il mio problema č che non riesco ad effettuare una semplice copia di un file
binario in tempi accettabili.
Nella copia di uno stesso file binario di byte 2,795,811, con il programma
C++ (riportato piů giů), il mio pc (linux_2.6.4, libc_2.3.2, libstdc++_3.0,
gcc_3.2.3) mi calcola un tempo di esecuzione medio di msec 120.
Invece con un altrettanto banale programma in C (in coda al messaggio), la
stessa copia si esegue mediamente in msec 55.
Non riesco a capire il motivo di questo degrado di prestazioni di oltre il
100%.
Devo usare altre funzioni?
Grazie in anticipo per qualsiasi aiuto.
----------- C++ -------------------
#include <fstream>
using namespace std;
int main()
{
    std::ifstream IN;
    IN.open("./filein_2795811B");
    std::ofstream OUT;
    OUT.open("./fileout_2795811B");
    OUT << IN.rdbuf();
    IN.close();
    OUT.close();
    return 0;
}
-----------------------------------------------
-------------- C --------------------------
# include <unistd.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <stdlib.h>
int main ()
{
	char block[4096];
	int in, out;
	int nread;
	in = open ("
file.in
", O_RDONLY);
	out = open ("file.out", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
	while ((nread = read(in, block, sizeof(block))) > 0)
		write (out, block, nread);
	close (in);
	close (out);
	exit (0);
}
------------------------- fine -------------------------------
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/




Scusatemi per avere inoltrato erroneamente due volte lo stesso messaggio. Ne
approfitto per segnalare che nel secondo programma, l'inclusione di unistd.h
e di stdlib.h non č necessaria.
Grazie ancora.
Fabio


 	char block[4096];
Prova a mettere qui ad esempio block[4] e vedrai che i tempi si 
avvicineranno (al peggiore)... Cosi capirai il problema... ;) 
-- 
Luc


Grazie Luc. In C aumento la velocità di lettura/scrittura utilizzando il
buffer di 4096 byte. Ho provato a fare in C++ qualcosa di simile usando qui
le funzioni read e write della libreria standard del C++. Il problema è che
ottengo il file di output troncato al multiplo di 4096 immediatamente
inferiore all'ampiezza del file di input (682*4096), cioè troncato a 2793472
byte. Come risolvere?



Mi spiego meglio con il listato successivo:
#include <fstream>
int main()
{
    char buffer[4096];
    std::ifstream IN ("./filein_2795811B");
    std::ofstream OUT ("./fileout_2795811B");
    while ((IN.read(&buffer,sizeof(buffer)) > 0)
            OUT.write(&buffer,sizeof(buffer));
    return 0;


 OUT.write(&buffer,sizeof(buffer))
Qui è l'errore. Non devi scrivere "sizeof(Buffer)" caratteri ma quelli 
effettivamente letti. Per ricavarli... leggi la doc su ifsream, ora io 
non ricordo. 
-- 
Luc

             OUT.write(&buffer,sizeof(buffer));
     while( IN.read( buffer,sizeof(buffer) )   )
     {
             OUT.write( buffer, IN.gcount()  );
     }
'read' restituisce un reference a *this. Per conoscere il numero di byte letti
usa gcount().
Max


Già provato purtroppo. Continua a spezzare il file ad un multiplo del buffer
(4096*682=2793472). Inoltre è lentissimo rispetto al codice C di cui al
primo messaggio (oltre il 100% di degrado nel tempo di esecuzione).
Mi sembra un argomento interessante da risolvere. Grazie comunque.


 Mi sembra un argomento interessante da risolvere.
Innanzitutto, l'implementazione in C stai utilizzando sfrutta delle API POSIX
che non appartengono al C standard (open, write, close). Non mi fa specie che
abbia prestazioni migliori.
In secondo luogo, se anche utilizzasse le funzioni standard del C (fopen,
fwrite, fclose), comunque potrei aspettarmi prestazioni migliori, giacché gli
stream sono solitamente implementati con chiamate alle funzioni C standard.
Max

 Max
Ho modificato il programma C++ dietro tua precisazione. Ho modificato anche
l'originale C per usare le funzioni ANSI C e non le POSIX.
Ovviamente con l'utilizzo di ANSI C ottengo tempi superiori di esecuzione
rispetto alle POSIX, ma in ogni caso rimangono di circa un 30% piů veloci
delle funzioni della libreria C++ (come tu stesso mi hai anticipato).
Vorrei capire se č quindi una regola da tenere in buon conto che nei
contesti in cui il tempo di esecuzione č fondamentale devi usare C e non
C++?
E poi in ambiente unix/linux in particolare non č meglio usare le funzioni
POSIX standard invece delle ANSI C?
Grazie.
Fabio


 primo messaggio (oltre il 100% di degrado nel tempo di esecuzione).
prova a profilare il codice per vedere quale e` il metodo che ciuccia
piu` tempo... [ e per informazioni su questo argomento direi che
it.comp.os.linux.developement e` piu` indicato]
-- 
Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it.
    - Brian W. Kernighan

 POSIX standard invece delle ANSI C?
Le funzioni ANSI C si differenziano dalle chiamate POSIX
per la modalità di buffering; infatti una write POSIX è:
write(filedes, &buff, dim_buff);
mentre la relativa "write" ANSI C è:
putc(intc, &FP);
fputc(intc, &FS);
Nella write POSIX cioè è possibile specificare il numero
di caratteri da utilizzare alla volta (e se vari dim_buff
da 1 a 4096 noterai le differenze...).
Le ANSI C si appoggiano spesso alle POSIX bufferizzando
i caratteri fino a che è possibile effettuare la scrittura
con il numero minimo (o "ottimizzato") di chiamate alla
write().
SiMoStro

 stream sono solitamente implementati con chiamate alle funzioni C
standard.
Ok. Fatte tutte le prove possibili con chiamate POSIX (read,write) e fuzioni
ANSI C (fread,fwrite) da un lato, e dall'altro lato fatto anche le prove in
C++ (read,write,OUT<<IN.rdbuf()) ho comparato i tempi di esecuzione C/C++,
che rimangono nettamente favorevoli al C con risparmi di oltre il 40% (nel
peggiore dei casi per C).
Fuori da ogni altra considerazione rimane una domanda:
Quando i tempi di esecuzione sono un "must", devo continuare ad usare C e
lasciare C++ alle situazioni in cui č preferibile scrivere codice piů
leggibile e manutenzionabile?
Fabio


 leggibile e manutenzionabile?
Non necessariamente. Presumo ci siano dei casi in cui il C++ e'
decisamente piu' veloce. L'unico che conosco direttamente
e' quello di qsort vs.  std::sort per i tipi elementari.
Se devi ordinare qualche milione di int o di double allora
usare il sort che c'e' in C++ e' piu veloce del qsort stardard
del c. Presumibilmente entrambi sono implementati come dei quicksort,
ma il qsort per fare i confronti deve chiamare ogni volta la
routine che gli hai passato tu, mentre il sort del c++
di fatto dovrebbe essere un template, e quindi permette al compilatore
di ottimizzare a seconda del tipo che deve ordinare, evitando anche
l'overhead delle chiamate, risultando
(almeno sul mio sistema) diverse volte piu' veloce quando
devo ordinare grosse quantita' di dati "semplici".
ciao,
g.

 da 1 a 4096 noterai le differenze...).
Dimenticavo (mi è venuto in mente leggendo l'altro post...),
la stessa cosa vale ovviamente anche per la fwrite che fornisce
solo la facilitazione - nel caso di dati binari - di specificare
le dimensioni ed il numero di elementi.
Se ti capita uno "Stevens" sotto le mani troverai due capitoli,
uno per le chiamate POSIX ed uno per le chiamate ANSI, in cui
sono spiegate per bene le differenze tra le due.
Personalmente uso sempre le POSIX, ormai più che altro per abitudine,
non mi è mai venuto in mente di verificarne le prestazioni :-)
SiMoStro


Non direi. Quello che rallenta sostanzialmente non e' il linguaggio C++, 
ma e' la libreria degli stream. Se compili il tuo programma C con un 
buon compilatore C++ dovresti ottenere pressoche' le stesse prestazioni.
Riformulerei la tua frase nel seguente modo:
Quando i tempi di esecuzione sono un "must", si devono usare le chiamate 
dirette al sistema operativo e lasciare le chiamate alla libreria 
standard del C++ alle situazioni in cui č preferibile scrivere codice 
piů manutenibile e portabile.
-- 
	Carlo Milanesi
 
http://digilander.libero.it/carlmila

 file binario in tempi accettabili.
Il problema non è tanto nel linguaggio (C o C++), ma nelle librerie usate
(la libreria iostream non è pensata per l'IO binario). Se usi linux la
soluzione più efficiente è usare la primitiva sendfile():
#include <sys/sendfile.h>
int source_file(open("file_sorgente",O_RDONLY));
int dest_file(open("file_destinatatario",O_WRONLY);
off_t offset(0);
int filesize=...;
sendfile(dest_file,source_file,&offset,filesize);
-- 
LF