0
votes

Le moyen le plus efficace (performances / temps) de trouver la valeur la plus élevée dans une liste avec des valeurs en constante évolution?

J'ai une application qui utilise des compteurs de performance pour obtenir la charge des cœurs / threads et trouver la valeur la plus élevée. Comme il y a normalement des threads 12/16/36 etc. de nos jours, j'ai utilisé une liste et un Math.Max ​​pour trouver la charge la plus élevée.

Cependant, l'intervalle de rafraîchissement est de 100 ms, il doit donc faire des calculs 600 fois par minute et je veux optimiser le code autant que possible, pour pouvoir aller avec un taux de rafraîchissement encore plus rapide.

Quelle est la manière la plus efficace de faire cela? J'ai lu le THREAD à ce sujet où les gens ont testé le efficacité, et alors que certains disent qu'il n'y a presque aucune différence entre Math.Max ​​et l'implémentation for / while / if, d'autres disent que lorsque vous travaillez avec des doubles ou des float (ce que j'ai), la différence est énorme, 0,3465041 sec pour en ligne implémentation et 6 sec pour Math.Max.

Alors, quelle sera la meilleure façon de faire les calculs à votre avis et comment cela peut-il être fait avec une liste? Merci d'avance! Voici ce que j'utilise ATM:

 private void maxThreadTimer_Tick(object sender, EventArgs e) //Max Thread Timer
    {
    float allCores1 = coreLoad1.NextValue();
    float allCores2 = coreLoad2.NextValue();
    float allCores3 = coreLoad3.NextValue();
    float allCores4 = coreLoad4.NextValue();
    float allCores5 = coreLoad5.NextValue();
    float allCores6 = coreLoad6.NextValue();
    float allCores7 = coreLoad7.NextValue();
    float allCores8 = coreLoad8.NextValue();
    float allCores9 = coreLoad9.NextValue();
    float allCores10 = coreLoad10.NextValue();
    float allCores11 = coreLoad11.NextValue();
    float allCores12 = coreLoad12.NextValue();
    float allCores13 = coreLoad13.NextValue();
    float allCores14 = coreLoad14.NextValue();
    float allCores15 = coreLoad15.NextValue();
    float allCores16 = coreLoad16.NextValue();

    List<float> valuesList = new List<float> { allCores1, allCores2, 
    allCores3, allCores4, allCores5, allCores6, allCores7, allCores8, 
    allCores9, allCores10, allCores11, allCores12, allCores13, allCores14, 
    allCores15, allCores16 };

    float tMax = valuesList.Max();
    }


8 commentaires

L'article auquel vous faites référence concerne Math.Max ​​() , pas IEnumerable.Max () .


... ce qui serait comme faire float max = coreLoad1.NextValue (); max = Math.Max ​​(max, coreLoad2.NextValue (); max = Math.Max ​​(max, coreLoad3.NextValue (); etc. Vous devrez mesurer les performances pour voir si cela fait une différence significative.


Je ne sais pas si cela fait une différence. Nu avec moi, s'il vous plaît, je suis un noob. La question reste donc intacte: quelle est la manière la plus efficace de la mettre en œuvre?


@DIYMods La liste est-elle uniquement créée dans le but de trouver la valeur maximale, ou est-elle réutilisée?


@ AndrewMorton uniquement pour trouver une valeur maximale


@DIYMods Et que fait-on de cette valeur maximale par la suite?


@ AndrewMorton Il est utilisé pour dessiner le graphique qui montre la charge de thread la plus élevée


@DIYMods Le temps nécessaire pour mettre à jour le graphique l'emporte probablement largement sur la recherche de la valeur maximale. Vous devez profiler votre programme pour trouver où des gains de vitesse réels et utiles peuvent être réalisés; le intégré des outils pourraient suffire.


3 Réponses :


0
votes

Je pense que vous avez besoin d'un SortedSet . Cela présente plusieurs avantages:

  1. Aucun doublon
  2. Toujours trié
  3. Générique, ce qui signifie que vous pouvez utiliser n'importe quel type
  4. Vous disposez des propriétés Max et Min

Pour en savoir plus, cliquez ici: https: / /docs.microsoft.com/en-us/dotnet/api/system.collections.generic.sortedset-1 .


0 commentaires

2
votes

J'aurais pensé que la grande majorité de la surcharge provenait des appels individuels à coreLoadX.NextValue () et que toute optimisation que vous apportez au code qui tente de trouver la valeur maximale sera ont peu d'effet notable.

Cela dit, pour le code que vous avez donné, la solution la plus performante est probablement:

float max = coreLoad1.NextValue();

float value = coreLoad2.NextValue();

if (value > max)
    max = value;

value = coreLoad3.NextValue();

if (value > max)
    max = value;

value = coreLoad4.NextValue();

if (value > max)
    max = value;

value = coreLoad5.NextValue();

if (value > max)
    max = value;

value = coreLoad6.NextValue();

if (value > max)
    max = value;

value = coreLoad7.NextValue();

if (value > max)
    max = value;

value = coreLoad8.NextValue();

if (value > max)
    max = value;

value = coreLoad9.NextValue();

if (value > max)
    max = value;

value = coreLoad10.NextValue();

if (value > max)
    max = value;

value = coreLoad11.NextValue();

if (value > max)
    max = value;

value = coreLoad12.NextValue();

if (value > max)
    max = value;

value = coreLoad13.NextValue();

if (value > max)
    max = value;

value = coreLoad14.NextValue();

if (value > max)
    max = value;

value = coreLoad15.NextValue();

if (value > max)
    max = value;

value = coreLoad16.NextValue();

if (value > max)
    max = value;

C'est juste votre variété commune ou jardin de "dérouler la boucle".


3 commentaires

Je suis juste curieux d'un concept. En supposant qu'il soit possible de créer une ArrayList de coreLoad au lieu d'avoir 16 objets coreLoad séparés, une boucle for serait-elle aussi efficace, voire même plus efficace que d'utiliser autant d'instructions if? Ou l'appel de valeurs via ArrayList et l'étape supplémentaire consistant à modifier la référence via ArrayList le ralentiraient-ils?


@JoshHeaps Chaque accès à un élément dans ArrayList nécessiterait un appel à une méthode d'indexation pour renvoyer la valeur (qui, étant donné une ArrayList, serait encadrée, ce qui signifierait en outre une opération de déballage - bien que l'utilisation d'un List au lieu de ArrayList éviterait cela). Ensuite, lorsque vous parcourez la liste, vous devez vérifier un index par rapport à la taille du tableau pour chaque itération. Et enfin, vous devrez TOUJOURS faire la comparaison de la valeur maximale actuelle avec chaque valeur du tableau. Donc, utiliser une ArrayList (ou une liste) le rendrait certainement plus lent.


c'est ce que je pensais. Beaucoup de gens m'ont juste dit qu'utiliser autant de déclarations if est une mauvaise chose que je suis toujours curieux de savoir si un moyen avec plus de déclarations if peut être meilleur ou non. Je recherche ces cas, et en voici un excellent. Merci!



1
votes

Créer une collection juste pour effectuer une opération Max va être une surcharge dont vous n'avez pas besoin, surtout si vous n'allez pas utiliser la collection plus tard. Créez une méthode locale qui suit le maximum au fur et à mesure que les éléments sont évalués. Cela finit par durer environ 150 ms sur un million d'itérations:

private void maxThreadTimer_Tick(object sender, EventArgs e)
{
    float tMax = 0;
    void TrackMax(float value)
    {
        if (value > tMax)
            tMax = value;
    }

    TrackMax(coreLoad1.NextValue());
    TrackMax(coreLoad2.NextValue());
    // etc etc etc
}


2 commentaires

Malheureusement, cette méthode charge le single-core à l'extrême. Méthode "si" - 4-5%, cette méthode 95-100%


Ensuite, vous avez autre chose en jeu ou faites quelque chose de mal. 100 millions d'itérations sur cette méthode et la méthode "if" montrent exactement le même profil de processeur.