Question

J'ai écrit un programme qui compte les lignes, les mots et les caractères dans un texte: il le fait avec des threads. Cela fonctionne très bien parfois, mais pas si bien d'autres fois. Ce qui finit par se produire, ce sont les variables indiquant le nombre de mots et de caractères comptés qui sont parfois succinctes et parfois non.

Il me semble que les discussions se terminent parfois avant de pouvoir compter tous les mots ou caractères qu’ils souhaitent. Est-ce parce que ces threads sortent du cadre lorsque la boucle while (true) se rompt?

J'ai inclus le code de la partie complexe de mon problème ci-dessous:

private void countText() {
  try {
    reader = new BufferedReader(new FileReader("this.txt"));
    while (true) {
      final String line = reader.readLine();
      if(line == null) {break;}
      lines++;
      new Thread(new Runnable() {public void run() {chars += characterCounter(line);}}).start();
      new Thread(new Runnable() {public void run() {words += wordCounter(line);}}).start();
      println(line);
    }

  } catch(IOException ex) {return;}

}

(Sous-question: C’est la première fois que je pose une question sur quelque chose et que je poste du code. Je ne veux pas utiliser StackOverflow à la place de Google et de Wikipédia et je crains que cette question ne soit pas appropriée? J’ai essayé pour que la question soit plus générale afin que je ne demande pas simplement de l'aide pour mon code ... mais existe-t-il un autre site Web où ce type de question serait peut-être plus approprié?)

Était-ce utile?

La solution

Une conception différente, basée sur un filetage, faciliterait la recherche et la résolution de ce type de problème et serait plus efficace à la vente. C'est une réponse longue, mais le résumé est "si vous travaillez en Java, consultez java.util.concurrent dès que humainement possible)".

Je suppose que vous codez plusieurs fois pour apprendre les threads plutôt que pour accélérer le comptage des mots, mais c'est une façon très inefficace d'utiliser les threads. Vous créez deux threads par ligne , deux mille threads pour un fichier de mille lignes. La création d'un thread (dans les machines virtuelles modernes) utilise des ressources du système d'exploitation et est généralement assez coûteuse. Lorsque deux - et encore moins deux mille threads doivent accéder à une ressource partagée (tels que vos compteurs chars et mots ), le conflit de mémoire résultant nuit également aux performances.

Synchronisation des variables de compteur comme Chris Kimpton suggère ou Atomic comme WMR suggère que corrigera probablement le code, mais aggravera également l’effet de conflit. Je suis à peu près sûr qu'il sera plus lent qu'un algorithme à un seul thread.

Je suggère de ne disposer que d'un fil de longue durée qui traite des caractères et d'un autre pour mots , chacun avec une file d'attente de travail dans laquelle vous soumettez des travaux chaque fois que vous le souhaitez. ajouter un nouveau numéro. De cette façon, un seul fil écrit sur chaque variable, et si vous modifiez la conception, il sera plus évident de déterminer qui est responsable de quoi. Ce sera également plus rapide car il n'y a pas de conflit de mémoire et vous ne créez pas des centaines de threads dans une boucle serrée.

Il est également important, une fois que vous avez lu toutes les lignes du fichier, d'attendre que tous les threads soient terminés avant d'imprimer réellement les valeurs des compteurs, sinon vous perdrez les mises à jour. à partir de discussions qui n'ont pas encore fini. Avec votre conception actuelle, vous devez créer une grande liste de threads que vous avez créés et la parcourir à la fin en vérifiant qu'ils sont tous morts. Avec une conception file-and-worker-thread, vous pouvez simplement dire à chaque thread de vider sa file d'attente, puis d'attendre que l'opération soit terminée.

Java (à partir de 1.5) rend ce type de conception très facile à mettre en oeuvre: consultez java.util.concurrent.Executors.newSingleThreadExecutor . Cela facilite également l'ajout ultérieur de plusieurs accès simultanés (en supposant un verrouillage approprié, etc.), car vous pouvez simplement passer à un pool de threads plutôt qu'à un seul thread.

Autres conseils

Comme Chris Kimpton l’a déjà souligné correctement, vous rencontrez un problème de mise à jour des caractères et des mots dans des threads différents. La synchronisation sur this ne fonctionnera pas non plus, car this est une référence au thread actuel, ce qui signifie que différents threads se synchroniseront sur des objets différents. Vous pouvez utiliser un "objet de verrouillage" supplémentaire. vous pouvez effectuer la synchronisation, mais la solution la plus simple consiste probablement à utiliser AtomicIntegers pour les 2 compteurs:

AtomicInteger chars = new AtomicInteger();
...
new Thread(new Runnable() {public void run() { chars.addAndGet(characterCounter(line));}}).start();
...

Cela résoudra probablement votre problème, plus par Sam Stoke réponse détaillée est tout à fait juste, la conception originale est très inefficace.

Pour répondre à votre question sur le moment où un fil de discussion "sort du cadre": vous démarrez deux nouveaux fils de discussion pour chaque ligne de votre fichier et ils seront tous exécutés jusqu'à la fin de leur run () méthode. C’est à moins que vous ne les fassiez démon threads) , dans ce cas, ils se fermeront dès que les threads de démon seront les seuls exécutés dans cette machine virtuelle.

Cela me semble être une bonne question ... Je pense que le problème pourrait être lié à l'atomicité des caractères + = et des mots + = - plusieurs threads pourraient appeler cela en même temps - faites-vous quelque chose pour vous assurer qu'il n'y a pas d'entrelacement.

C'est-à-dire:

Le fil 1, avec chars = 10, veut ajouter 5

Sujet 2, a des caractères = 10, veut ajouter 3

Le fil 1 travaille sur un nouveau total, 15

Le fil 2 établit un nouveau total, 13

Le fil 1 définit les caractères sur 15

Le fil 2 définit les caractères à 13.

Peut-être possible à moins d'utiliser Synchronisé lors de la mise à jour de ces vars.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top