5 votes

Comment Array.ForEach() se compare-t-il à la boucle for standard en C# ?

Je me languis de l'époque où, en tant que programmeur C, je savais taper :

memset( byte_array, '0xFF' );

et obtenir un tableau d'octets rempli de caractères 'FF'. J'ai donc cherché une solution de remplacement :

for (int i=0; i < byteArray.Length; i++)
{
    byteArray[i] = 0xFF;
}

Dernièrement, j'ai utilisé certaines des nouvelles fonctionnalités de C# et j'ai utilisé cette approche à la place :

Array.ForEach<byte>(byteArray, b => b = 0xFF);

Certes, la seconde approche semble plus propre et plus agréable à l'œil, mais quelles sont les performances par rapport à la première approche ? Est-ce que j'introduis des frais généraux inutiles en utilisant Linq et les génériques ?

Merci, Dave

7voto

Mike Points 981
Array.ForEach<byte>(byteArray, b => b = 0xFF);

Cela ne fait rien du tout. Il met une copie de chaque octet à 0xFF, il n'est jamais mis dans le tableau.

Pour un moyen plus simple de procéder, vous pouvez essayer

Enumerable.Repeat((byte)0xFF, someCount).ToArray();

pour initialiser votre tableau

Repeat sera certainement plus lent que votre boucle for. Selon le lien posté par CAbbott dans un commentaire, elle est plus lente d'environ 10,5 secondes (12,38 contre 1,7) sur un tableau de plus d'un million d'éléments, mais ce n'est pas une grande différence si vous ne le faites que quelques fois avec de petits tableaux.

Vous pouvez écrire une méthode simple qui sera plus rapide que Repeat et ToArray car vous pouvez connaître la longueur du tableau avant de commencer à le remplir.

  public static T[] GetPreFilledArray<T>(T fillItem, int count)
  {
       var result = new T[count];
       for(int i =0; i < count; i++)
       {
           result[i] = fillItem;
       }
       return result;
  }

  byte[] byteArray = GetPreFilledArray((byte)0xFF, 1000);

Cette option devrait être assez rapide, puisque c'est essentiellement ce que vous faites maintenant.

4voto

Guffa Points 308133

La deuxième méthode utilise un délégué pour définir chaque octet, ce qui signifie qu'il y a un appel de méthode pour chaque octet du tableau. C'est beaucoup de frais généraux juste pour définir un octet.

La boucle simple, quant à elle, est plutôt bien optimisée par le compilateur. Il déterminera que l'index ne peut pas être en dehors du tableau, donc il ignorera la vérification des limites.

Pour clarifier : vous n'utilisez pas du tout LINQ. La méthode ForEach est une méthode de la classe Array, et elle est antérieure à l'ajout de LINQ.

1voto

Digicoder Points 844

Buffer.BlockCopy est ce que j'ai tendance à utiliser lorsque je veux un comportement de type memset/memcpy. Je mesurerais les performances et utiliserais quelque chose comme reflector. Il se peut qu'en interne le langage appelle les classes intégrées, qui à leur tour sont des enveloppes minces autour de MEMCPY et MEMSET.

1voto

Lucero Points 38928

Si vous recherchez la performance comme le type qui a posté la question à laquelle CAbott a fait référence, vous pouvez jeter un coup d'oeil à ma réponse que je viens de poster là .

0voto

Randolpho Points 36512

À moins que vous ne fassiez cela pendant une opération très critique en termes de performances, vous n'aurez pas de problème. Il existe de nombreux benchmarks concernant les appels foreach par rapport à l'itération indexée, et la différence est minime.

Bien sûr, vous pouvez toujours l'évaluer vous-même...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X