2009-10-10 6 views
7

Quel est un moyen efficace pour une application multithread Java où plusieurs threads doivent lire exactement le même fichier (> 1 Go en taille) et l'exposer comme un flux d'entrée? J'ai remarqué que s'il y a beaucoup de threads (> 32), le système commence à se disputer sur les E/S et a beaucoup d'E/S attendues.Java multithreading la lecture d'un seul fichier

J'ai envisagé de charger le fichier dans un tableau d'octets partagé par tous les threads - chaque thread créerait un ByteArrayInputStream, mais l'allocation d'un tableau d'octets de 1 Go ne fonctionnerait pas correctement.

J'ai également envisagé d'utiliser un seul FileChannel et chaque thread créant un InputStream par-dessus en utilisant Channels.newInputStream(), mais il semble que c'est le FileChannel qui maintient l'état pour InputStream.

+1

Chaque thread a-t-il besoin de tout le contenu du fichier? Ou chacun peut-il rechercher les données pertinentes dont il a besoin? –

+0

Chaque thread doit lire le fichier entier. – bob

+0

Le système a 8 Go de mémoire, et cela ne me dérangerait pas d'allouer un tableau de 1 Go. Mais la JVM ne semble pas aimer cela - elle utilise 100% de CPU essayant d'allouer le tableau pendant très longtemps. – bob

Répondre

10

Il me semble que vous allez avoir pour charger le fichier en mémoire si vous voulez éviter les conflits d'E/S. Le système d'exploitation fera une mise en mémoire tampon, mais si vous trouvez que ce n'est pas suffisant, vous devrez le faire vous-même.

Est-ce que vous avez vraiment besoin de 32 threads au? Je présume que vous n'avez pas près que beaucoup de cœurs - donc utiliser moins de threads et vous aurez moins le changement de contexte, etc.

Faites vos fils traiter tous les fichiers du début à la fin? Si oui, pourriez-vous diviser efficacement le fichier en morceaux? Lisez le premier (disons) 10 Mo de données en mémoire, laissez tous les threads le traiter, puis passez aux 10 Mo suivants, etc.

Si cela ne fonctionne pas pour vous, combien de mémoire avez-vous par rapport à la taille du fichier? Si vous avez beaucoup de mémoire, mais que vous ne voulez pas allouer un énorme tableau, vous pouvez lire le fichier entier en mémoire, mais dans beaucoup de tableaux séparés d'octets plus petits. Vous devrez alors écrire un flux d'entrée qui couvre tous ces tableaux d'octets, mais cela devrait être faisable.

+0

@jon, serait-il possible d'utiliser les outils nio pour mapper une structure Java au fichier sur le disque alors tout ce qui est nécessaire est d'écrire la structure java et de laisser la JVM/OS comprendre comment gérer les détails de lecture réels ? –

+1

@Thorbjorn: Eh bien Java prend en charge les fichiers mappés en mémoire, mais si vous avez plus d'informations que le système d'exploitation sur la façon dont vous allez utiliser le fichier, vous pourrez peut-être faire mieux. –

1

Quelques idées:

  1. écrire une intégration InputStream personnalisée qui agit comme une vue sur un FileChannel. Ecrivez ceci de telle sorte qu'il ne repose sur aucun état dans FileChannel. (ie: chaque instance doit garder une trace de sa propre position et lire devrait utiliser des lectures absolues sur le FileChannel sous-jacent.) Cela vous évite au moins les problèmes que vous aviez avec Channels.newInputStream(), mais cela peut ne pas résoudre vos problèmes de contention. .

  2. Ecrire une implémentation InputStream personnalisée qui agit comme une vue sur un MappedByteBuffer. Le mappage de la mémoire ne devrait pas être aussi mauvais que de lire tout le contenu dans la mémoire à la fois, mais vous allez toujours manger jusqu'à 1 Go d'espace d'adressage virtuel.

  3. Identique # 1, mais ont une sorte de couche de mise en mémoire cache partagée. Je ne voudrais pas essayer ceci à moins que 1 s'avère être pas assez efficace et 2 n'est pas réalisable. Vraiment, le système d'exploitation devrait déjà faire de la mise en cache pour vous dans # 1, alors ici, vous essayez essentiellement d'être plus intelligent que la mise en cache du système de fichiers du système d'exploitation.

5

Vous pouvez ouvrir le fichier plusieurs fois en mode lecture seule. Vous pouvez accéder au fichier comme vous le souhaitez. Laissez simplement la mise en cache sur le système d'exploitation. Quand c'est trop lent, vous pouvez envisager une sorte de mise en cache basée sur les segments où tous les threads peuvent accéder au même cache.

0

C'est un très gros fichier. Pouvez-vous obtenir le fichier livré sous la forme d'un plus petit ensemble de fichiers? Juste livrer ce fichier sera un gros travail, même sur un réseau d'entreprise.

Il est parfois plus facile de modifier le processus que le programme.

Vous pouvez même être mieux d'écrire quelque chose pour diviser le fichier en un certain nombre de morceaux et les traiter séparément.