Lequel des codes suivants est le plus rapide/la meilleure pratique pour convertir un objet x?
int myInt = (int)x;
ou
int myInt = Convert.ToInt32(x);
ou
int myInt = Int32.Parse(x);
ou dans le cas d'une chaîne 's'
int myInt;
Int32.TryParse(s, out myInt);
Je suis curieux de savoir lequel fonctionne le plus rapidement pour les types de données qui ont une méthode dans Convert, pas seulement les entiers. Je viens d'utiliser int comme exemple.
Edit: Ce cas est né de la récupération d'informations à partir d'une table de données. Est-ce que (int) fonctionnera toujours le plus rapidement?
D'après certains tests, lorsque l'objet x = 123123123, int est le plus rapide, comme beaucoup l'ont dit. Lorsque x est une chaîne, Parse s'exécute le plus rapidement (remarque: cast lève une exception). Ce que je suis vraiment curieux, c'est comment ils fonctionnent lorsque la valeur est récupérée de la manière suivante:
foreach(DataRow row in someTable.Rows)
{
myInt = (int)row["some int value"];
myInt2 = Int.Parse(row["some int value"]);
myInt2 = Convert.ToInt32(row["some int value"]);
}
Pourquoi ne l'essayez-vous pas quelques milliers de fois?
(cela vaut pour toutes les questions "Quel est le plus rapide:")
Hmmm, beaucoup de votes négatifs au fil des ans ... Je suppose que je devrais développer cette réponse.
La déclaration ci-dessus a été faite avec une certaine désinvolture dans ma jeunesse, mais je suis toujours d'accord avec son sentiment. Cela ne vaut pas la peine de passer du temps à créer une SO question demandant aux autres ce qu'ils pensent être plus rapide sur deux ou trois opérations qui prennent moins de 1 ms chacune.
Le fait que l'un puisse prendre un cycle ou deux de plus que l'autre sera presque certainement négligeable dans l'utilisation quotidienne. Et si vous remarquez un problème de performances dans votre application lorsque vous convertissez des millions d'objets en pouces, c'est le point où vous pouvez profiler le réel et vous pourrez facilement tester si la conversion int est réellement le goulot d'étranglement.
Et alors qu'aujourd'hui c'est le convertisseur objet-int, demain vous penserez peut-être que votre convertisseur objet-DateTime prend beaucoup de temps. Souhaitez-vous créer une autre SO question pour savoir quelle est la méthode la plus rapide?
Quant à votre situation (sans doute résolue depuis longtemps), comme mentionné dans un commentaire, vous interrogez une base de données, donc la conversion objet-int est le moindre de vos soucis. Si j'étais vous, j'utiliserais l'une des méthodes de conversion que vous avez mentionnées. Si un problème survient, j'isolerais l'appel à l'aide d'un profileur ou de la journalisation. Ensuite, quand je remarque que la conversion objet-int est effectuée un million de fois et que le temps total pris par cette conversion semble relativement élevé, je changerais pour utiliser une méthode de conversion différente et recalculer. Choisissez la méthode de conversion qui prend le moins de temps. Vous pouvez même tester cela dans une solution distincte, ou même LINQPad, ou Powershell, etc.
Si x est un entier encadré alors (int)x
Est le plus rapide.
Si x est une chaîne mais est définitivement un nombre valide, alors int.Parse(x)
est préférable
Si x est une chaîne mais qu'elle n'est peut-être pas valide, int.TryParse(x)
est beaucoup plus rapide qu'un bloc try-catch.
La différence entre Parse et TryParse est négligeable dans toutes les boucles sauf les très grandes.
Si vous ne savez pas ce qu'est x (peut-être une chaîne ou un entier encadré) alors Convert.ToInt32(x)
est le meilleur.
Ces règles généralisées sont également valables pour tous les types de valeur avec des méthodes Parse et TryParse statiques.
le plus rapide! = Meilleure pratique!
Par exemple, (int)
Est presque certainement le plus rapide car c'est un opérateur plutôt qu'un appel de fonction, mais cela ne fonctionnera que dans certaines situations.
La meilleure pratique consiste à utiliser le code le plus lisible qui n'aura pas d'impact négatif sur vos performances, et 99 fois sur 100, une conversion entière ne conduit pas les performances de votre application. Si c'est le cas, utilisez la conversion la plus appropriée et la plus étroite possible. Parfois, c'est (int)
. Parfois, c'est TryParse()
. Parfois, c'est Convert.ToInt32()
.
Si vous savez que les données sont définitivement int, alors int myInt = (int)x;
devrait être l'option la plus rapide. Sinon, TryParse
vous aidera à bien faire les choses sans la lenteur des exceptions.
BTW:
(int) ne déballe donc plus vite,
(int) IL =
.locals init (
[0] object x,
[1] int32 Y)
L_0000: ldc.i4.1
L_0001: box int32
L_0006: stloc.0
L_0007: ldloc.0
L_0008: unbox int32
L_000d: ldobj int32
L_0012: stloc.1
L_0013: ret
Convert.Toint32 =
.locals init (
[0] object x,
[1] int32 Y)
L_0000: ldc.i4.1
L_0001: box int32
L_0006: stloc.0
L_0007: ldloc.0
L_0008: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)
L_000d: call int32 [mscorlib]System.Convert::ToInt32(object)
L_0012: stloc.1
L_0013: ret
Lorsque j'ai des questions sur les différences de performances entre différentes façons de faire quelque chose de spécifique comme celui-ci, je crée généralement une nouvelle entrée dans ma copie de MeasureIt, un téléchargement gratuit à partir d'un grand article MSDN de Vance Morrison. Pour plus d'informations, veuillez vous référer à l'article.
En ajoutant un simple bout de code à MeasureIt, j'obtiens les résultats ci-dessous qui comparent les temps réels des différentes méthodes de conversion en int. Notez que le transtypage de la chaîne en int lèvera une exception et n'est pas valide, donc j'ai juste ajouté les permutations qui avaient du sens pour moi.
Nom Médiane Moyenne StdDev Min Max Samples IntCasts: Copy [count = 1000 scale = 10.0] 0.054 0.060 0.014 0.054 0.101 10 IntCasts: Cast Int [count = Échelle 1000 = 10,0] 0,059 0,060 0,007 0,054 0,080 10 IntCasts: objet moulé [nombre = échelle 1000 = 10,0] 0,097 0,100 0,008 0,097 0,122 10 IntCasts: int.Parse [nombre = échelle 1000 = 10,0] 2,721 3,169 0,850 2,687 5,473 10 IntCasts: Convert.ToInt32 [nombre = échelle 1000 = 10,0] 3,221 3,258 0,067 3,219 3,418 10
Pour trouver les meilleures performances pour les différents types qui vous intéressent, étendez simplement le code ci-dessous, qui est littéralement tout ce que j'avais à ajouter à MeasureIt pour générer le tableau ci-dessus.
static unsafe public void MeasureIntCasts()
{
int result;
int intInput = 1234;
object objInput = 1234;
string strInput = "1234";
timer1000.Measure("Copy", 10, delegate
{
result = intInput;
});
timer1000.Measure("Cast Object", 10, delegate
{
result = (int)objInput;
});
timer1000.Measure("int.Parse", 10, delegate
{
result = int.Parse(strInput);
});
timer1000.Measure("Convert.ToInt32", 10, delegate
{
result = Convert.ToInt32(strInput);
});
}
La meilleure pratique serait TryParse, et voir le résultat de cela, si cela fonctionnait - sinon vous pourriez obtenir des exceptions
Lors de l'optimisation d'une grille de données liée dans .Net 2, j'ai trouvé que près de la moitié du temps était consacré aux méthodes ToString () de divers objets qui étaient ensuite utilisées comme entrées des opérations de conversion. En isolant ces cas et en convertissant le type correct dans la mesure du possible (étant donné qu'il s'agissait de lignes extraites d'une base de données et que les types pouvaient être fiables), cela a provoqué une augmentation massive de la vitesse de cette opération de liaison de données.
Donc, si vous connaissez le type de la chose à l'avance et que vous frapperez le morceau de code suffisamment de fois, cela vaut la peine de le lancer directement au lieu de le convertir si nécessaire.
En étendant le test d'Eric Cosky par alternatives de Sam Allen , j'ai trouvé que si vous savez que votre chaîne est un entier valide, l'analyse syntaxique par vous-même est beaucoup plus rapide.
J'ai prolongé le test par les cas suivants:
timer1000.Measure("IntParseFast", 10, delegate
{
result = Misc.IntParseFast(strInput);
});
timer1000.Measure("IntParseUnsafe", 10, delegate
{
result = Misc.IntParseUnsafe(strInput);
});
Avec les implémentations suivantes:
public static int IntParseFast(string value)
{
int result = 0;
int length = value.Length;
for (int i = 0; i < length; i++)
{
result = 10 * result + (value[i] - 48);
}
return result;
}
public unsafe static int IntParseUnsafe(string value)
{
int result = 0;
fixed (char* v = value)
{
char* str = v;
while (*str != '\0')
{
result = 10 * result + (*str - 48);
str++;
}
}
return result;
}
J'obtiens les résultats suivants:
IntCaint.Parse 5,495
IntCaConvert.ToInt32 5,653
IntCaIntParseFast 1,154
IntCaIntParseUnsafe 1,245
ce n'est pas vrai. La conversion rapide est castée directement:
int i = (int) stringData;
watch.Elapsed = {00:00:00.1732388}
watch2.Elapsed= {00:00:00.0878196}
// Mesary start
Stopwatch watch = new Stopwatch();
watch.Start();
for (int f = 1; f < 1000000; f++)
{
item.Count = FastInt32.IntParseFast(dt.Rows[i]["TopCount"]);
} // Execute the task to be timed
watch.Stop();
Console.WriteLine("Elapsed: {0}", watch.Elapsed);
Console.WriteLine("In milliseconds: {0}", watch.ElapsedMilliseconds);
Console.WriteLine("In timer ticks: {0}", watch.ElapsedTicks);
// Mesary end
// Mesary start
Stopwatch watch2 = new Stopwatch();
watch2.Start();
for (int n = 1; n < 1000000; n++)
{
item.Count = (int)(dt.Rows[i]["TopCount"]);
} // Execute the task to be timed
watch2.Stop();
Console.WriteLine("Elapsed: {0}", watch2.Elapsed);
Console.WriteLine("In milliseconds: {0}", watch2.ElapsedMilliseconds);
Console.WriteLine("In timer ticks: {0}", watch2.ElapsedTicks);
// Mesary end
Je ne suis pas sûr des performances, mais ces méthodes ne sont pas du tout les mêmes. Parse
et TryParse
fonctionnent avec la chaîne, la représentation String
d'un objet est analysée (voir MSDN).
Convertit la représentation sous forme de chaîne d'un nombre en son équivalent entier signé 32 bits.
Vous n'êtes pas sûr de la conversion et de la classe Convert
, mais la diffusion concerne uniquement les objets qui sont déjà des nombres entiers, mais pas fortement typés.
Matthias
Quelqu'un a déjà fait l'analyse comparative. Voici les résultats. La manière la plus rapide si vous savez ce que vous convertissez sera toujours un entier valide, est de utilisez la méthode suivante (à laquelle quelques personnes ont répondu ci-dessus):
int value = 0;
for (int i = 0; i < str.Length; i++)
{
value = value * 10 + (str[i] - '0');
}
Les autres techniques qui étaient comparées étaient:
Si vous aviez besoin de la vitesse supplémentaire, il serait facile de tester les différentes options. Puisque vous ne les testez pas, vous ne devez pas en avoir besoin. Ne perdez pas votre temps avec des micro-optimisations inutiles!
La conversion (int) sur chaîne ne fonctionnera pas, donc je ne la teste pas. Convert.ToInt32 se reflète comme testant la valeur à null et ALORS appelant int.Parse, donc devrait en général avoir tendance à être plus lent que int.Parse ().
foreach(DataRow row in someTable.Rows)
{
myInt = (int)row["some int value"];
myInt2 = Int.Parse(row["some int value"]);
myInt2 = Convert.ToInt32(row["some int value"]);
}
Pour cet exemple, si la valeur provenant de la table est en effet une valeur int, ou une valeur de base de données comparable, alors en utilisant le
myInt = (int)row["some int value"];
serait le plus efficace, et donc le "plus rapide", car il
row["some int value"];
sera une instance int de type valeur encadrée dans une instance d'objet de type référence, donc l'utilisation du transtypage de type explicite sera le plus rapide car d'autres personnes ont dit qu'il s'agit d'une opération et non d'un appel de fonction, réduisant ainsi les opérations de processeur requises. Un appel à une méthode de conversion ou d'analyse nécessiterait des opérations CPU supplémentaires et ne serait donc pas aussi "rapide".