J'essaie de déterminer s'il y a une différence de performances (ou d'avantages) lorsque nous utilisons nio FileChannel
par rapport FileInputStream/FileOuputStream
à la normale pour lire et écrire des fichiers sur le système de fichiers. J'ai observé que sur ma machine, les deux fonctionnent au même niveau, aussi souvent la FileChannel
manière est plus lente. Puis-je connaître plus de détails en comparant ces deux méthodes. Voici le code que j'ai utilisé, le fichier avec lequel je teste est autour 350MB
. Est-ce une bonne option d'utiliser des classes basées sur NIO pour les E / S de fichiers, si je ne regarde pas l'accès aléatoire ou d'autres fonctionnalités avancées?
package trialjavaprograms;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class JavaNIOTest {
public static void main(String[] args) throws Exception {
useNormalIO();
useFileChannel();
}
private static void useNormalIO() throws Exception {
File file = new File("/home/developer/test.iso");
File oFile = new File("/home/developer/test2");
long time1 = System.currentTimeMillis();
InputStream is = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(oFile);
byte[] buf = new byte[64 * 1024];
int len = 0;
while((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.flush();
fos.close();
is.close();
long time2 = System.currentTimeMillis();
System.out.println("Time taken: "+(time2-time1)+" ms");
}
private static void useFileChannel() throws Exception {
File file = new File("/home/developer/test.iso");
File oFile = new File("/home/developer/test2");
long time1 = System.currentTimeMillis();
FileInputStream is = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(oFile);
FileChannel f = is.getChannel();
FileChannel f2 = fos.getChannel();
ByteBuffer buf = ByteBuffer.allocateDirect(64 * 1024);
long len = 0;
while((len = f.read(buf)) != -1) {
buf.flip();
f2.write(buf);
buf.clear();
}
f2.close();
f.close();
long time2 = System.currentTimeMillis();
System.out.println("Time taken: "+(time2-time1)+" ms");
}
}
java
optimization
file
nio
operations
Keshav
la source
la source
transferTo
/transferFrom
serait plus conventionnel pour la copie de fichiers. Quelle que soit la technique qui ne devrait pas rendre votre disque dur plus rapide ou plus lent, même si je suppose qu'il pourrait y avoir un problème si elle lisait de petits morceaux à la fois et obligeait la tête à passer un temps excessif à chercher.Réponses:
Mon expérience avec des fichiers de plus grande taille a été
java.nio
plus rapide quejava.io
. Solidement plus rapide. Comme dans la plage> 250%. Cela dit, j'élimine les goulots d'étranglement évidents, dont je pense que votre micro-référence pourrait souffrir. Domaines potentiels à étudier:La taille du tampon. L'algorithme que vous avez fondamentalement est
Ma propre expérience a été que cette taille de tampon est mûre pour le réglage. J'ai choisi 4 Ko pour une partie de mon application, 256 Ko pour une autre. Je soupçonne que votre code souffre d'un tampon aussi important. Exécutez des tests de performance avec des tampons de 1 Ko, 2 Ko, 4 Ko, 8 Ko, 16 Ko, 32 Ko et 64 Ko pour vous le prouver.
N'effectuez pas de tests de performances Java qui lisent et écrivent sur le même disque.
Si vous le faites, alors vous comparez vraiment le disque, et non Java. Je suggérerais également que si votre processeur n'est pas occupé, vous rencontrez probablement un autre goulot d'étranglement.
N'utilisez pas de tampon si vous n'en avez pas besoin.
Pourquoi copier en mémoire si votre cible est un autre disque ou une carte réseau? Avec des fichiers plus volumineux, la latence encourue n'est pas triviale.
Comme d'autres l'ont dit, utilisez
FileChannel.transferTo()
ouFileChannel.transferFrom()
. Le principal avantage ici est que la JVM utilise l'accès du système d'exploitation au DMA ( Direct Memory Access ), s'il est présent. (Cela dépend de l'implémentation, mais les versions modernes de Sun et d'IBM sur les processeurs à usage général sont bonnes à faire.) Ce qui se passe, c'est que les données vont directement vers / depuis le disque, vers le bus, puis vers la destination ... en contournant tout circuit via RAM ou CPU.L'application Web sur laquelle j'ai passé mes journées et mes nuits à travailler est très lourde en IO. J'ai aussi fait des micro-benchmarks et des benchmarks du monde réel. Et les résultats sont sur mon blog, jetez un œil:
Utiliser les données et les environnements de production
Les micro-benchmarks sont sujets à la distorsion. Si vous le pouvez, faites l'effort de collecter des données à partir de ce que vous prévoyez de faire exactement, avec la charge attendue, sur le matériel que vous attendez.
Mes benchmarks sont solides et fiables car ils se sont déroulés sur un système de production, un système costaud, un système sous charge, rassemblés en logs. Pas le disque SATA 7200 tr / min 2,5 "de mon ordinateur portable alors que je regardais intensément la JVM travailler sur mon disque dur.
Sur quoi courez-vous? Cela compte.
la source
Si la chose que vous voulez comparer est la performance de la copie de fichiers, alors pour le test de canal, vous devriez le faire à la place:
Cela ne sera pas plus lent que de vous mettre en mémoire tampon d'un canal à l'autre et sera potentiellement beaucoup plus rapide. Selon les Javadocs:
la source
Sur la base de mes tests (Win7 64bit, 6 Go de RAM, Java6), NIO transferFrom est rapide uniquement avec de petits fichiers et devient très lent sur des fichiers plus volumineux. Le retournement du tampon de données NIO surpasse toujours les E / S standard.
Copie de 1 000 x 2 Mo
Copie 100x20mb
Copie 1x1000mb
La méthode transferTo () fonctionne sur des morceaux d'un fichier; n'était pas conçu comme une méthode de copie de fichiers de haut niveau: comment copier un fichier volumineux sous Windows XP?
la source
Répondre à la partie «utilité» de la question:
Un piège assez subtil de l'utilisation de
FileChannel
overFileOutputStream
est que l'exécution de l'une de ses opérations de blocage (par exempleread()
ouwrite()
) à partir d'un thread qui est dans un état interrompu provoquera la fermeture brusque du canal avecjava.nio.channels.ClosedByInterruptException
.Maintenant, cela pourrait être une bonne chose si tout ce qui a
FileChannel
été utilisé fait partie de la fonction principale du thread, et la conception en a tenu compte.Mais cela peut aussi être embêtant s'il est utilisé par une fonctionnalité auxiliaire telle qu'une fonction de journalisation. Par exemple, vous pouvez trouver votre sortie de journalisation soudainement fermée si la fonction de journalisation est appelée par un thread également interrompu.
C'est dommage que ce soit si subtil car ne pas en tenir compte peut entraîner des bogues qui affectent l'intégrité en écriture. [1] [2]
la source
J'ai testé les performances de FileInputStream par rapport à FileChannel pour le décodage des fichiers encodés en base64. Dans mes expériences, j'ai testé des fichiers assez volumineux et io traditionnel était toujours un peu plus rapide que nio.
FileChannel pourrait avoir eu un avantage dans les versions précédentes du jvm en raison de la surcharge de synchronisation dans plusieurs classes liées à io, mais jvm moderne est assez bon pour supprimer les verrous inutiles.
la source
Si vous n'utilisez pas la fonction transferTo ou les fonctions non bloquantes, vous ne remarquerez pas de différence entre les E / S traditionnelles et NIO (2) car les E / S traditionnelles sont mappées à NIO.
Mais si vous pouvez utiliser les fonctionnalités NIO telles que transferFrom / To ou si vous souhaitez utiliser des tampons, alors bien sûr NIO est la voie à suivre.
la source
Mon expérience est que NIO est beaucoup plus rapide avec de petits fichiers. Mais quand il s'agit de fichiers volumineux, FileInputStream / FileOutputStream est beaucoup plus rapide.
la source
java.nio
c'est plus rapide avec des fichiers plus volumineux quejava.io
, pas plus petits.java.nio
est rapide tant que le fichier est suffisamment petit pour être mappé en mémoire. S'il s'agrandit (200 Mo et plus),java.io
c'est plus rapide.FileChannel.read()
. Il n'y a pas qu'une seule approche pour lire les fichiers en utilisantjava.nio
.