12
votes

Problèmes sporadiques dans la gestion d'un projet Java multi-thread à Win7

Je travaille sur un projet à la fois de la mémoire et de la calcul intensive. Une partie importante de l'exécution utilise la multi-threading par un fixeTheadpool code>. Bref; Je dispose 1 em> fil d'extraction de données à partir de plusieurs emplacements distants (à l'aide de connexions URL) et de remplir un blockingQueue code> avec des objets à analyser et n em> threads qui Choisissez ces objets et exécutez l'analyse. EDIT: voir le code ci-dessous strong>

Cette configuration fonctionne comme un charme sur ma machine Linux exécutant OpenSUse 11.3, mais un collègue le teste sur une machine très similaire en cours d'exécution Win7 obtient Notifications personnalisées des délais d'attente forts> sur l'interrogation de la file d'attente (voir le code ci-dessous), beaucoup d'entre eux réellement. J'ai essayé de surveiller l'utilisation du processeur sur sa machine, et il semble que le logiciel ne reçoit pas plus de 15% des CPU tandis que sur ma machine, l'utilisation du processeur frappe le toit, comme je l'ai voulu. P>

Ma question est que cela peut-il être un signe de "famine" de la file d'attente? Pourrait-il être pour que le fil du producteur ne reçoit pas assez de temps de processeur? Si oui, comment puis-je continuer à donner un fil particulier dans la priorité plus élevée de la piscine? P>

mise à jour: strong> J'essaie d'identifier le problème, sans joie ... je l'ai fait de nouvelles idées. p>

  • Profilage de l'exécution du code avec Jvisalvm démontre un comportement très particulier. Les méthodes sont appelées dans des rafales courtes de la CPU-Time avec plusieurs secondes d'aucun progrès entre les deux. Cela signifie que l'OS est en quelque sorte frapper les freins sur le processus. P> Li>

  • désactivation des démons anti-virus et de sauvegarde n'a aucun effet significatif sur la question p> li>

  • Modification de la priorité de Java.exe (la seule instance) via Task Manager (Informé ici ) ne changent rien non plus. (Cela étant dit, je ne pouvais pas donner la priorité «en temps réel» à Java, et devait être satisfait de «Prio High») P> Li>

  • Profilage de l'utilisation du réseau montre un bon déroulement de données dedans et je devine donc que ce n'est pas le goulot d'étranglement (alors qu'il s'agit d'une partie considérable du temps d'exécution du processus, mais que je connais déjà et est à peu près le même pourcentage que possible sur ma machine Linux). P> li> ul>

    Des idées sur la manière dont Win7 OS pourrait limiter le temps de la CPU à mon projet? Si ce n'est pas le système d'exploitation, quel pourrait être le facteur limitant? Je voudrais encore insister sur le fait que la machine n'exécute aucun autre calcul intensive en même temps et il n'ya presque aucune charge sur les CPU autres que mon logiciel. Cela me rend fou ... p>

    Modifier: Code correspondant strong> p>

    public ConcurrencyService(Dataset d, QueryService qserv, Set<MyObject> s){
    
        timeout = 3;
        this.qs = qserv;
        this.bq = qs.getQueue();
        this.ds = d;
        this.analyzedObjects = s;
        this.drc = DebugRoutineContainer.getInstance();
        this.started = false;
    
        int nbrOfProcs = Runtime.getRuntime().availableProcessors();
        poolSize = nbrOfProcs;
        pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(poolSize);
        drc.setScoreLogStream(new PrintStream(qs.getScoreLogFile()));
    }
    
    public void serve() throws InterruptedException {
        try {
            this.ds.initDataset();
            this.started = true;
            pool.execute(new QueryingAction(qs));
            for(;;){
                MyObject p = bq.poll(timeout, TimeUnit.MINUTES);
    
                if(p != null){
                    if (p.getId().equals("0"))
                        break;
    
                    pool.submit(new AnalysisAction(ds, p, analyzedObjects, qs.getKnownAssocs()));
                }else 
                    drc.log("Timed out while waiting for an object...");
    
            }
    
          } catch (Exception ex) {
                ex.printStackTrace();
                String exit_msg = "Unexpected error in core analysis, terminating execution!";
    
          }finally{
                drc.log("--DEBUG: Termination criteria found, shutdown initiated..");
                drc.getMemoryInfo(true);    // dump meminfo to log
    
                pool.shutdown();
    
                int mins = 2;
                int nCores = poolSize;
                long    totalTasks = pool.getTaskCount(), 
                        compTasks = pool.getCompletedTaskCount(),
                        tasksRemaining = totalTasks - compTasks,
                        timeout = mins * tasksRemaining / nCores;
    
                drc.log("--DEBUG: Shutdown commenced, thread pool will terminate once all objects are processed, " +
                            "or will timeout in : " + timeout + " minutes... \n" + compTasks + " of " +  (totalTasks -1) + 
                            " objects have been analyzed so far, " + "mean process time is: " +
                            drc.getMeanProcTimeAsString() + " milliseconds.");
    
                pool.awaitTermination(timeout, TimeUnit.MINUTES);
          }
    
    }
    


6 commentaires

Peut-être que le système d'exploitation lui-même limite vos quotas de ressources?


pourrait être le cas, mais je ne suis pas assez familier avec Win7 pour vérifier si c'est le cas, des suggestions sur la façon de vérifier que c'est le cas ??


Combien de threads de consommation utilisez-vous? Avez-vous essayé de réduire le nombre à 1 et d'augmenter progressivement pour voir comment la situation évolue?


À l'heure actuelle, la piscine == Nombre de cœurs disponibles. Je n'ai pas essayé de réduire le nombre de threads surtout parce qu'il fonctionne à pleine accélérateur lorsque vous utilisez un jeu de données plus petit sur cette machine. Outre une autre machine, il semble de ne pas avoir de problèmes du tout. Donc, je ne pense vraiment pas que ce soit le nombre de threads, mais comment le système d'exploitation gère les fils. Mais bien sûr, si je n'obtiens pas d'autres indices, je finirai par essayer de voir si cela fait une différence pour diminuer le nombre de fils dans la piscine.


Ok, de votre description, il semble s'agir d'un problème de conflit de la famine / de verrouillage. Avez-vous essayé de changer la structure de données simultanée en un autre?


Qu'est-ce que signifie "times de vote"? L'utilisation de la piscine habituelle doit masquer toute la gestion de la file d'attente à l'intérieur, votre producteur vient d'imposer des runnables appropriés à l'intérieur de la piscine. Si vous l'utilisez de manière plus softistie (en faisant du traitement faite à la main, comme cela me semble de votre description) - s'il vous plaît, clarifiez-la. Peut-être que le code Snippet aidez-nous à comprendre le problème


8 Réponses :


3
votes

Je soupçonne que le thread du producteur ne reçoit pas / charge les données source assez rapidement. Cela pourrait ne pas être un manque de CPU mais un problème connexe de l'IO. (Je ne sais pas pourquoi vous avez des temps de temps sur votre blocageQueue)

Cela pourrait valoir la peine d'avoir un fil qui enregistre périodiquement des choses comme le nombre de tâches ajoutées et la longueur de la file d'attente (par exemple toutes les 5-15 secondes)


1 commentaires

Bien que je suis d'accord avec vous qu'il est fort probable que le fil du producteur ne "produisait pas" assez rapide, je ne reçois pas ce qui pourrait être la raison de ce comportement différentiel sur deux machines apparemment identiques (à l'exception du système d'exploitation). En ce qui concerne la file d'attente; C'est en fait que j'enregistre mes délais d'attente de l'appel suivant: myobj p = bq.poll (délai d'attente, timeDunit.minutes);



1
votes

priorité ne vous aidera pas, car le problème n'est pas une question de décider qui obtient des ressources précieuses - l'utilisation des ressources n'est pas maximale. La seule façon dont le fil du producteur ne recevrait pas assez de temps de processeur est s'il n'était pas prêt à courir. La priorité ne vous aidera pas, car le problème n'est pas un problème.

Combien de cœurs la machine a-t-elle? Il est possible que le fil du producteur fonctionne à toute vitesse et qu'il ne suffit pas de suffire à la CPU. Il est également possible que le producteur est I / O lié.


5 commentaires

Les deux machines sont i7 avec 4Cores et hyper filetage (ressemblant à 8 noyaux au système d'exploitation). Nous sommes assis dans le même bâtiment physique et le même étage, probablement sur le même commutateur. Je ne suis donc pas sûr de savoir s'il y a une différence drastique entre les E / S avec le monde en dehors des cases. :) Je suppose que Win7 a beaucoup plus de threads associés au système d'exploitation, ce qui pourrait être la raison pour laquelle les choses ne se produisent pas aussi efficacement que sur Linux. Cependant, ce n'est qu'un sentiment d'intestin et je ne peux pas sauvegarder de quelque manière que ce soit :)


La meilleure façon de la comprendre est de regarder en détail ce qui se passe sur sa machine.


Juste pour clarifier, vous suggérez de profiler le JVM lors de l'exécution du logiciel, par exemple avec Jvisalvm? Ou faites-vous référence à une autre façon de le regarder en détail?


Je ne recommande aucun outil particulier. Mais vous avez besoin d'un moyen de dire où se passe la CPU, que votre fil de producteur soit en marche ou en attente de quelque chose, et ainsi de suite.


Je vois ce que vous voulez dire, j'ai essayé de profiler l'exécution du logiciel (voir modification) pour avoir une meilleure idée de ce qui se passe. Bien que cela ait donné des idées, je ne sais toujours pas ce qui se passe vraiment au lieu de chiffrer :)



1
votes

Vous pouvez essayer de séparer le thread du producteur de la piscine (c.-à-d. Créer un thread distinct et définir le pool pour avoir -1 la capacité actuelle), puis définir sa priorité au maximum via SetPriptriority . Voir ce qui se passe, bien que la priorité explique rarement une telle différence de performance.


3 commentaires

C'est ce que je pensais aussi, mais je ne suis pas sûr que si c'est une méthode souhaitée. J'ai lu un certain nombre de messages sur Ainsi, ainsi que sur d'autres sources, conseillant d'utiliser directement le fil directement. Mais je devine que ce sera mon dernier recours.


@Posdef: Tant que cela résout le problème et que vous ne vous mêlez pas de gérer à la fois le producteur et les consommateurs comme des entités différentes, alors je ne conseillerai personnellement pas contre cette stratégie. Mais comme je l'ai dit, il est difficile de croire que la priorité est le seul facteur ici ...


Je suppose que je finirai par mettre fin à la mise en œuvre, dans une future version de logiciels, mais comme mentionné dans mon édition, ce n'est pas le seul problème en ce moment. Apparemment, il existe des problèmes plus graves dans le code que si le fil du producteur est dans la piscine. :(



1
votes

Lorsque vous dites une connexion URL, voulez-vous dire local ou distant? Il se peut que la vitesse du réseau ralentit votre producteur


1 commentaires

C'est une connexion à distance. Cependant, comme je l'ai mentionné, je doute fortement que ce soit le réseau, car les machines Linux et Win ont une quincaillerie comparable et sont assis sur le même réseau physique. Outre le profilage du réseau montre un beau flux de données élevé élevé (presque) constant.



0
votes

Je penserais que c'était une question spécifique du système d'exploitation car c'est la différence de base entre les deux unités. Plus spécifiquement, quelque chose ralentit les données arrivant à travers la connexion distante.

Trouver un outil d'analyse de la circulation telle que Wireshark et / ou NetWorx et essayez de découvrir s'il y a quelque chose d'étrangler le PC gagnant. Peut-être que cela traverse un proxy qui a une sorte de capuchon de taux configuré.


0 commentaires

3
votes

Donc, si je comprends correctement votre problème, vous avez un thread pour récupérer des données et plusieurs threads pour analyser les données récupérées. Votre problème est que les threads ne sont pas correctement synchronisés pour fonctionner ensemble et tirer pleinement parti du processeur.

Vous avez un problème de producteur Tipical-consommateur avec un seul producteur et plusieurs consommateurs. Je vous conseille de refaire votre code un peu pour avoir, à la place, plusieurs threads de consommation indépendants qui attendent toujours que des ressources soient disponibles et que ce n'est que courant. De cette façon, vous garantissez l'utilisation maximale du processeur.

thread de consommateur: xxx

thread de producteur: xxx < P> Vous voyez cela de cette façon, vos discussions effectuent toujours un travail utile ou dormir. Ceci est juste un projet de code pour illustrer. Voir plus d'explications ici: http://www.javamex.com/tatudials/wait_notify_how_to.shtmlled Et ici: http://www.java-samples.com/showtutorial.php? TutorialID = 306


2 commentaires

Merci pour la réponse et je vais regarder dans les détails. Mais il semble que vous ne manquiez pas un point très crucial et important; Mon code obtient une puissance complète du processeur lorsque je l'exécute sur ma machine ou une autre machine qui exécute Win7. Ce que je demande, c'est la raison de la performance différentielle sur ces machines similaires (matérielles).


J'ai eu les mêmes problèmes il y a quelques années, lorsque vous travaillez sur un projet qui fonctionnerait dans plusieurs OSS. La différence que vous obtenez est due aux planificateurs de fil des systèmes d'exploitation. Bien que la machine virtuelle Java traite de la planification, il s'agit toujours du système d'exploitation qui dicte lorsque le JVM fonctionne et lorsqu'il peut accéder aux systèmes distants que vous utilisez. Il est très difficile de spécifier la différence de comportement, et je pense que vous risquez de perdre votre temps pour essayer de le découvrir. En fin de compte, ce sera toujours la faute de votre code. Essayez mon approche et dites-moi si vous remarquez une amélioration.



1
votes

Alors, après des semaines de violon, de lutte dans le code et d'autres types de souffrance, je pense avoir une percée, "un moment de clarté" si vous voulez ...

J'ai réussi à montrer que le programme peut présenter le même comportement lent sur ma machine Linux et peut effectivement courir une accélération complète sur la machine Win-7 problématique. Le creux du problème semble être une sorte de corruption des fichiers système / cache utilisé pour stocker les résultats des requêtes précédentes et globalement, accélérer l'analyse. Vous devez aimer l'ironie, dans ce cas, ils semblaient être la raison de l'analyse lente extrême. En rétrospective, j'aurais dû savoir (un rasoir de La Occam) ...

Je ne suis toujours pas sûr de la manière dont la corruption se produit, mais au moins, elle n'est probablement pas liée à différents systèmes d'exploitation. L'utilisation des fichiers système de ma machine augmente la sortie de l'hôte Win7 jusqu'à environ 40% uniquement. Processus Le processus davantage a également révélé que, curieusement, il y a beaucoup plus d'activité de GC sur Win7, ce qui a apparemment pris beaucoup de temps de processeur du nombre de chiffres. Donner -xmx2g prend en charge la collecte excessive des ordures et la consommation de la CPU pour le processus tire jusqu'à 95-96%, et les threads fonctionnent en douceur.

Maintenant que ma question initiale est répondue, je dois dire que la réactivité globale Java est définitivement meilleure sur l'environnement Linux, même sans attribuer plus de mémoire de tas, je peux facilement multi-tâches pendant que je suis une analyse approfondie en arrière-plan. Les choses ne sont pas aussi lisses dans Win-7, E.x. Redimensionnement de l'interface graphique est significativement lent une fois que l'analyse décolle à pleine vitesse.

Merci pour toutes les réponses, je suis désolé pour la description des problèmes partiellement trompeurs. J'ai simplement partagé ce que j'ai découvert tout en déboguant au mieux de mes capacités. Quoi qu'il en soit, je crois que la générosité se rend à Peter Lawrey, puisqu'il a tôt l'impression d'une émission d'E / S et c'était sa suggestion sur un fil d'enregistrement qui m'a finalement conduit à la réponse.


0 commentaires

0
votes

désolé pas vraiment une réponse mais ne correspondait pas à l'intérieur du commentaire et il vaut toujours la lecture, je pense:

  • Eh bien, je ne suis pas java sympathique
  • Mais j'ai récemment le même problème avec les projets C ++ pour le contrôle de la machine via USB.
  • sur XP ou W2K va parfaitement pendant des mois de fonctionnement 24h / 24 et 7j / 7 sur une ou plusieurs machines noyau
  • sur W7 et une machine assez forte, tout va bien, mais parfois (CCA 1x par quelques heures) gèle pendant quelques secondes sans raison évidente.
  • sur la machine W7 et relativement faible (2 notes 1,66 GHz T2300e Notebook) Les threads gèlent un peu de temps et exécutent à nouveau qui sous-traite / débordent de l'USB / Win / app Fifos et de l'affaissement de la communication ...
    • Il semble que rien ne soit bloqué, mais le W7 Sheduler ne donne que de la CPU aux bons threads occasionnels.
    • Je pensais que la communication du pilote USB (Jungo) gèle le bourgeon qui n'est pas vrai que je l'ai mesuré et c'est OK même dans Freeze
    • Le gel était d'environ 6-15 secondes CCA une fois par minute.
    • Après avoir ajouté des dormeurs de sécurité aux filetages des boucles, le gel a de courte distance à environ 0,5 sec
    • mais toujours là
    • Même si l'application n'est pas sous / débordant des FIFOS le côté du pilote USB Windows (peu de fois par minute pour quelques ms)
    • Changement de la priorité et de la classe des exe / threads n'affecte pas la performance sur W7 (sur XP, W2K Travail tel qu'il devrait)

      Comme vous pouvez le constater, il semble que nous avons le plus probablement le même problème. Dans mon cas:

      • n'est pas associé à une connexion (lorsque je remplace le fil USB avec la simulation du périphérique, il se comporte similaire)
      • Ajout de sommeil au code critique aide beaucoup
      • erreur est présente également dans le nombre faible de threads [2 fast (17ms) + 1 lent (250ms) + code d'application = 4]
      • Ma consommation de CPU sur W7 Slow Machine n'est pas non plus à 100%, mais environ 95%, ce qui est correct car j'ai dort partout
      • Mes applications utilisent environ 40-100 Mo de mémoire, mais le calcul de la CPU exige ...
        • Mais pas autant que cela pourrait fonctionner en toute sécurité sur de nombreuses machines plus lentes
        • Mais à cause de la connexion du pilote USB et de la prise en charge de plusieurs périphériques, il a besoin d'au moins 2 cœurs
        • Ma prochaine étape consiste à ajouter une sorte de temps d'exécution de l'enregistrement / d'analyse pour voir ce qui se passe plus en détail
        • et aussi peu de réécriture de fils d'envoi / réception pour voir si cela aide

          Quand j'apprends quelque chose de nouveau / utile l'ajoutera.


0 commentaires