Y a-t-il un moyen plus rapide de le faire en utilisant c #? Je me souviens d'utiliser C ++, il y avait quelque chose appelé Memset () code> pour faire ce genre de choses ... p> p>
3 Réponses :
J'ai écrit la méthode qui n'est pas plus rapide, mais cela fonctionne avec des tableaux multidimensionnels réels, non seulement 2D.
public static class ArrayExtensions { public static void Fill(this Array array, object value) { var indicies = new int[array.Rank]; Fill(array, 0, indicies, value); } public static void Fill(Array array, int dimension, int[] indicies, object value) { if (dimension < array.Rank) { for (int i = array.GetLowerBound(dimension); i <= array.GetUpperBound(dimension); i++) { indicies[dimension] = i; Fill(array, dimension + 1, indicies, value); } } else array.SetValue(value, indicies); } }
double[,] myArray = new double[x, y]; if( parallel == true ) { stopWatch.Start(); System.Threading.Tasks.Parallel.For( 0, x, i => { for( int j = 0; j < y; ++j ) myArray[i, j] = double.PositiveInfinity; }); stopWatch.Stop(); Print( "Elapsed milliseconds: {0}", stopWatch.ElapsedMilliseconds ); } else { stopWatch.Start(); for( int i = 0; i < x; ++i ) for( int j = 0; j < y; ++j ) myArray[i, j] = double.PositiveInfinity; stopWatch.Stop(); Print("Elapsed milliseconds: {0}", stopWatch.ElapsedMilliseconds); } When setting x and y to 10000 I get 553 milliseconds for the single-threaded approach and 170 for the multi-threaded one.
Un tableau multidimensionnel n'est qu'un gros bloc de mémoire, afin que nous puissions le traiter comme un, similaire à la manière dont résultats: p> Mais ces chiffres s'appliquent uniquement à un tableau de 1000x1000. Lorsque vous modifiez la taille de la matrice, les résultats diffèrent. Par exemple, lorsque nous modifions la taille de la matrice à 10000x10000, les résultats de tous les points de repère dangereux sont très proches. Probablement parce qu'il y a plus de récupérations de mémoire pour le plus grand tableau qu'il a tendance à égaliser les plus petites améliorations itératives observées dans les trois derniers points de repère. P> Il y a une leçon là-bas quelque part, mais je voulais surtout juste partager ces résultats , puisque c'était une expérience assez amusante à faire. P> p> memset () code> fonctionne. Cela nécessite un code dangereux. Je ne dirais pas que ça vaut la peine d'être fait à moins que ce soit vraiment em> performance critique. C'est un exercice amusant, cependant, voici quelques points de repère utilisant BenchmarkDototnet:
multidimensionalarrayloop code> est lent en raison de la vérification des limites. Le JIT émet un code chaque boucle qui veille à ce que
[i, j] code> est à l'intérieur des limites de la matrice. Le JIT peut élier parfois la vérification des limites, je sais que cela fait pour les tableaux monocensionnels. Je ne sais pas si cela le fait pour plusieurs dimensions multidimensionnelles. P>
multidimensionalarraynessunsafeloop code> est essentiellement le même code que
multidimensionalarrayloop code> mais sans vérification sans bornes. C'est considérablement plus rapide, prenant 40% du temps. Il est considéré comme «naïf», cependant, car la boucle pourrait toujours être améliorée en déroulant la boucle. P>
multidimensionnelleLill code> n'a pas non plus de vérification des limites et est plus ou moins la même chose Comme
Multidimensionalarraynessunsafeloop Code>, Toutefois,
Span.frillez Code> Entièrement déroulant de la boucle, c'est pourquoi c'est un peu plus rapide que notre boucle naïve dangereuse. Cela ne prend que 30% du temps comme notre original. P>
Multidimensionnalsefill code> améliore notre première boucle dangereuse en faisant deux choses: boucle déroulante et vectorisante. Cela nécessite une CPU avec support SSE2, mais cela nous permet d'écrire 128 bits (16 octets) dans une seule instruction. Cela nous donne un coup de pouce supplémentaire de vitesse, en l'emportant jusqu'à 22% de l'original. Fait intéressant, cette même boucle avec AVX (256 bits) était toujours plus lente que la version SSE2, de sorte que la référence ne soit pas incluse ici. P>
La façon dont vous avez l'air bien. Avec C #, vous ne plaisantez pas avec la mémoire elle-même, elle est manipulée pour vous. Il peut y avoir une autre syntaxe disponible pour cela, mais ce ne sera pas plus rapide une fois compilé.
Est-ce purement académique ou est-ce le goulot d'étranglement i> dans votre code? Il faut environ 1,2sec à remplir ~ 2GB de doubler sur ma boîte. Cela étant dit, il semble que cela ne soit fait que si cela ne devrait être fait qu'une fois dans une application afin que 1,2sec ne soit pas tout ce mal.
Je suis d'accord avec Kingcronus. Il existe différentes façons de le faire, mais aucun d'entre eux ne sera essentiellement plus rapide ni plus efficace que ce que vous avez affiché. Vous demandiez probablement s'il y avait un moyen de déclarer ces valeurs lorsque vous initialisez le tableau ... Il n'y a pas un que j'ai trouvé. Le tableau doit initialiser à la double valeur par défaut.
Pour dire la vérité, je n'ai pas testé la vitesse de mon code. Je pensais qu'il devrait y avoir une autre façon qui sera plus rapide (par exemple, une manière parallèle, etc.). Cependant, il s'avère que cela est raisonnablement rapide et je n'ai besoin d'aucune autre façon de faire la même chose. Merci.
@Zagy Si vous avez la parallélisée, vous seriez plus que probablement blessé i> performance, pas l'aide. Le goulot d'étranglement est le bus de mémoire, pas la CPU. Si vous parallélisez cela, vous obtiendrez simplement à la mémoire de la mémoire, ce qui sera ralentissez-le i> car il est spécifiquement conçu pour optimiser l'accès à des blocs de mémoire séquentielle. En plus de cela, vous ajoutez les frais généraux de la gestion des threads.
@Servy: génial que! Code plus rapide et plus simple. Mon préféré!