7
votes

Remplir un tableau multidimensionnel avec les mêmes valeurs C #

Y a-t-il un moyen plus rapide de le faire en utilisant c #? XXX

Je me souviens d'utiliser C ++, il y avait quelque chose appelé Memset () pour faire ce genre de choses ...


6 commentaires

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 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é 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 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é!


3 Réponses :


1
votes

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);
    }
}


0 commentaires

1
votes
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.

0 commentaires

4
votes

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 memset () fonctionne. Cela nécessite un code dangereux. Je ne dirais pas que ça vaut la peine d'être fait à moins que ce soit vraiment performance critique. C'est un exercice amusant, cependant, voici quelques points de repère utilisant BenchmarkDototnet: xxx

résultats: xxx

multidimensionalarrayloop est lent en raison de la vérification des limites. Le JIT émet un code chaque boucle qui veille à ce que [i, j] 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.

multidimensionalarraynessunsafeloop est essentiellement le même code que multidimensionalarrayloop 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.

multidimensionnelleLill n'a pas non plus de vérification des limites et est plus ou moins la même chose Comme Multidimensionalarraynessunsafeloop , Toutefois, Span.frillez 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.

Multidimensionnalsefill 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.

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.

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.


0 commentaires