question est simple
est ce code p> même rapide que ce code p> sens commun Moi qu'il devrait être plus rapide de rechercher la référence dans le dictionnaire une fois et rangez-la quelque part afin de ne pas avoir besoin de regarder plusieurs fois, mais je ne sais pas vraiment comment fonctionne le dictionnaire. P> Alors est-ce plus rapide ou pas? Et pourquoi? P> p>
3 Réponses :
Oui, vous êtes correct. Votre première approche fait que le dictionnaire recherche 4 fois, alors que le second le fait une fois. La seconde est définitivement meilleure. P>
Cependant, dans la vie réelle, une recherche de dictionnaire est ridiculement rapide, alors si vous n'avez pas eu un dictionnaire massif, la différence ne sera pas perceptible, peut-être même pas mesurable. P>
Remarque La taille du dictionnaire n'est pas pertinente ici, car les recherches sont O (1). Tout ce qui compte, c'est combien de recherches que vous faites, donc si ce code est dans une boucle qui fonctionne un grand nombre de fois (même si le dictionnaire étant levé n'est pas grand), il pourrait alors compter.
Notable, probablement pas. Mesurable, certainement. Le code doit calculer la valeur hachage et faire une recherche. De plus, la taille du dictionnaire est hors de propos. Vous recherchez quelque chose dans un dictionnaire de 1 000 000 articles ne prendra plus que dans un dictionnaire de seulement 1 000 articles. Sauf si le dictionnaire est plein (facteur de charge élevé). Ensuite, cela agit plus comme une recherche séquentielle.
Pour le plaisir, j'ai créé des dictionnaires de 1 000 et 1 000 000 articles à plusieurs reprises, puis 5 000 000 recherches sur elles (clé GUID). Il a fallu environ 2,5 secondes pour effectuer les recherches contre 1 000 articles et 3,5 secondes pour les faire contre 1 000 000 articles. Résultats très cohérents. Donc, je dirais que la taille du dictionnaire compte, bien que pas de façon spectaculaire.
@Jimmischel Vous avez raison, il doit être mesurable d'une certaine manière. Mais éventuellement pas mesurable en millisecondes, même pour beaucoup de recherches réelles de la vie réelle, ce que j'avais à l'esprit. Mais il est si facile d'optimiser cela que je ne le sauterais pas simplement parce que cela ne sera probablement pas un facteur.
@Joeenos dans votre test de performance, avez-vous consulté le même article, ou c'était des éléments aléatoires?
@niry il y a trois ans et demi, je ne pense pas que j'ai encore ce code ... mais il devrait être assez facile de recréer si vous voulez l'essayer.
J'étais curieux. Le test de l'unité suivant (éventuellement) montre que la deuxième méthode est d'environ 25% plus rapide. (121 ms vs 91 ms). Aller de 6 champs à 2 réduit l'écart, 40 ms vs 33 ms. Je dis éventuellement depuis que j'ai écrit cela assez rapidement et je ne suis pas convaincu qu'il est immunisé de mesurer un effet secondaire, mais cela montre le comportement attendu, alors pourquoi la questionnera. (hah).
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Diagnostics;
namespace TestProject1
{
public class DataObject
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string D { get; set; }
public string E { get; set; }
public string F { get; set; }
}
[TestClass]
public class UnitTest1
{
public static Dictionary<string, DataObject> dict = new Dictionary<string, DataObject>();
static string lookie;
[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext) {
Random rand = new Random(123545);
for (int i = 0; i < 10000; i++)
{
string key = rand.NextDouble().ToString();
DataObject dob = new DataObject();
dict.Add(key, dob);
if (i == 4567)
lookie = key;
}
}
[TestMethod]
public void TestMethod()
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int j = 0; j < 100000; j++)
{
dict[lookie].A = "val" + j;
dict[lookie].B = "val" + j;
dict[lookie].C = "val" + j;
dict[lookie].D = "val" + j;
dict[lookie].E = "val" + j;
dict[lookie].F = "val" + j;
}
sw.Stop();
System.Diagnostics.Debug.WriteLine(sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
for (int j = 0; j < 100000; j++)
{
DataObject dob = dict[lookie];
dob.A = "val" + j;
dob.B = "val" + j;
dob.C = "val" + j;
dob.D = "val" + j;
dob.E = "val" +j;
dob.F = "val" +j;
}
sw.Stop();
System.Diagnostics.Debug.WriteLine(sw.ElapsedMilliseconds);
}
}
}
Avez-vous fait les timings sur une version de sortie sans débogueur attachée? 25% semble ... excessif.
Joe est absolument juste, mais comme si cela ne suffisait pas, j'ai fait un test évident simple: sur ma machine ces sorties à: p> Avoir seulement 1 recherche réduit définitivement le temps total des grands nombres. P> P>
Donc, environ 1,3 seconde, différence sur 10 millions d'itérations? C'est à peu près la définition de «bas du bruit», en ce qui concerne l'optimisation du programme.
Avoir vous i> effectivement essayé de tester s'il existe une différence de vitesse?
pourquoi ne pas exécuter un test de référence et voir
Non je n'ai pas, je n'ai aucune idée de savoir comment le code de référence
@Petr disant que vous n'avez aucune idée de comment faire quelque chose dans la programmation est comme néo dans la matrice disant qu'il ne sait pas
kung-fu code>. Il suffit de faire une recherche Google de 30 secondes et de Voila.Eh bien, vous écrivez d'abord quelque chose comme
DateTime StarTime = DateTime.now code>. Et puis vous écrivez le code que vous souhaitez comparer, puis vous écrivezdatetime dt = datetime.now.frames - starttime.frames code>La vitesse n'est guère pertinente dans un cas comme celui-ci, mais je penserais que vous avez raison, le dernier est le plus rapide, même s'il pourrait dépendre du nombre de propriétés (ou de champs) que vous devez attribuer à. Est-ce vraiment quatre? Je pense que vous devriez choisir à quelle jamais vous préférez. La vitesse n'est pas importante ici.
@Samiam Il serait préférable d'utiliser la classe
chronomètre code> que pour s'appuyer surdatetime.now code>. En outre, en .net leDateTime code> STRUT n'a pas deCadres code> Propriété. Vous pouvez directement soustraire deux valeurs code> DateTime code> (le résultat étant unTimespan code> valeur).Est-ce une certitude que ces deux approches génèrent même un code IL différent?
@Samiam Je suis un débutant pour analyser, mais je sais qu'il existe plusieurs optimisations derrière l'exécution du code et les résultats ne sont pas toujours clairs. Par exemple, dans ce cas même, le compilateur pouvait simplement modifier le code sur ce que j'ai dans le deuxième bloc, pour le rendre plus rapide, mais ce cas complexe, il le laisserait comme il l'est (donc dans un cas je ne verrais aucune différence de vitesse et Dans un autre cas, il pourrait y en avoir certains). C'est pourquoi je demande ici, les gens qui connaissent vraiment la réponse, plutôt que d'essayer de le calculer moi-même
@Samiam je pense que vous voulez
ticks code>, pascadres code>, non? Et je suis d'accord avec @jeppestignielsen - lechronomètre code> a été conçu pour cela, alors j'irais avec elle.Non, le compilateur n'est pas autorisé à "optimiser" le premier code dans l'équivalent du deuxième code, car
valeurs code> est un champpublic code> et que le compilateur ne peut pas savoir si certains L'autre thread sera en cours d'exécution qui modifie l'entrée pour"foo" code>, il doit donc rechercher à chaque fois si vous demandez cela.