La lecture et l'écriture de plusieurs fichiers en parallèle
J'ai besoin d'écrire un programme en Java qui va lire un nombre relativement important (~50 000 habitants) des fichiers dans une arborescence de répertoires, de traiter les données de sortie et les données traitées dans un document distinct (plat) répertoire.
Actuellement, j'ai quelque chose comme ceci:
private void crawlDirectoyAndProcessFiles(File directory) {
for (File file : directory.listFiles()) {
if (file.isDirectory()) {
crawlDirectoyAndProcessFiles(file);
} else {
Data d = readFile(file);
ProcessedData p = d.process();
writeFile(p,file.getAbsolutePath(),outputDir);
}
}
}
Il suffit de dire que chacune de ces méthodes est enlevé et ramené pour en faciliter la lecture, mais ils fonctionnent tous très bien. L'ensemble du processus fonctionne bien, sauf qu'il est lent. Le traitement des données se fait par l'intermédiaire d'un service à distance et prend entre 5 et 15 secondes. Multipliez-le par de 50 000...
Je n'ai jamais fait quoi que ce soit multi-thread avant, mais je me dis que je peux obtenir une assez bonne vitesse augmente, si je ne. Quelqu'un peut-il donner quelques conseils sur comment je peux paralléliser cette méthode?
Vous n'êtes pas susceptible d'obtenir toute accélération de parallélisation d'une tâche qui est presque certain d'être disque. Sauf si vous essayez de paralléliser les répertoires qui sont sur différents disques physiques...
Faites-vous la sortie vers un fichier ou sur un fichier par fichier ?
Les fichiers sont des fichiers d'images de différentes tailles (de quelques ko à quelques mo) . Le traitement prend la part du lion du moment cependant. La production est actuellement à plusieurs fichiers (un pour chaque fichier traité, dans un format de texte), mais je voudrais aussi idéalement que d'écrire quelque chose pour chaque entrée dans un fichier journal. L'ordre n'est pas important.
OriginalL'auteur Trasvi | 2012-01-05
Vous devez vous connecter pour publier un commentaire.
Je voudrais utiliser un ThreadPoolExecutor pour gérer les threads. Vous pouvez faire quelque chose comme ceci:
Vous obtenir un Exécuteur testamentaire, à l'aide de:
où
poolSize
est le nombre maximal de threads que vous souhaitez aller à la fois. (Il est important d'avoir un nombre raisonnable ici; de 50 000 threads n'est pas exactement une bonne idée. Un nombre raisonnable pourrait être de 8.) Notez qu'après avoir mis en file d'attente tous les fichiers, votre thread principal peut attendre jusqu'à ce que les choses sont faites en appelantexecutor.awaitTermination
.Bon point; je conseille
ExecutorService.awaitTermination()
ces jours cet exemple fonctionne mieux avec une fourchette rejoindre la piscine, qui peut être utilisé avec
new ForkJoinPool(numprocs)
avec une attendent de résiliation. Les processus les plus gourmands en fait le mieux avec ces piscines alors que les petites processus comme une séquence de fibonacci peut être mieux avec un singlethread ou d'un fil exécuteur testamentaire (mieux avec correctement géré code personnalisé).OriginalL'auteur Ted Hopp
En supposant que vous avez un seul disque dur (c'est à dire quelque chose qui ne permet simultanée des opérations de lecture, pas un SSD ou une matrice RAID, système de fichiers en réseau, etc...), alors vous voulez un thread d'exécution d'e /s (lecture de/écriture sur le disque). En outre, vous ne voulez que de nombreux threads faire en CPU, les opérations que vous avez cœurs, sinon de temps sera perdu dans la commutation de contexte.
Donné les restrictions ci-dessus, le code ci-dessous devrait fonctionner pour vous. Le thread simple exécuteur assure que seul un
Runnable
s'exécute à un moment donné. Le corrigé du pool de threads assure pas plus d'NUM_CPUS
Runnable
s sont en cours d'exécution à tout moment.Une chose ce n'est pas faire est de fournir de la rétroaction sur lorsque le traitement est terminé.
_fileReaderWriter.execute(new FileWriter(_file, processedData));
, c'est un appel asynchrone?Oui, il ajoute une nouvelle tâche à la
_fileReaderWriter
's de la file d'attente pour être exécutée sur l'un de ses fils.Alors, comment voulez-vous attendre que les fils à la fin? Je voudrais faire une autre action une fois qu'ils sont tous fait
OriginalL'auteur SimonC
Le plus simple (et sans doute l'un des plus raisonnable) est de disposer d'un pool de thread (prendre un coup d'oeil correspondante à l'Exécuteur testamentaire). Thread principal est responsable de ramper dans le répertoire. Lorsqu'un fichier est rencontrée, puis de créer un "Job" (qui est un Exécutable/Callable) et de laisser l'Exécuteur gérer le travail.
(Cela devrait être suffisant pour vous de commencer, je préfère ne pas donner trop de béton code coz il ne devrait pas être difficile pour vous de comprendre une fois que vous avez lu l'Exécuteur testamentaire, Rachetable etc partie)
OriginalL'auteur Adrian Shum