104 votes

Quel est l'équivalent de memset en C #?

J'ai besoin de remplir un byte[] avec un seul non nulle valeur. Comment puis-je faire cela en C# sans boucle dans chaque byte dans le tableau?

Mise à jour: Les commentaires semblent avoir partagé ce en deux questions -

  1. Est-il un Cadre de la méthode pour remplir un byte[] qui pourrait être apparenté memset
  2. Quel est le moyen le plus efficace de le faire lorsque nous sommes face à un très grand tableau?

Je suis totalement d'accord que l'utilisation d'une simple boucle fonctionne bien, comme Eric et d'autres l'ont fait. Le point de la question était de voir si je pouvais apprendre quelque chose de nouveau à propos de C# :) je pense que Juliette méthode pour un fonctionnement en Parallèle devrait être encore plus rapide qu'une simple boucle.

Repères: Merci à Mikael Svenson: http://techmikael.blogspot.com/2009/12/filling-array-with-default-value.html

Il s'avère que la simple for boucle est la voie à suivre, sauf si vous souhaitez utiliser le code unsafe.

Des excuses pour ne pas être plus clair dans mon post original. Eric et Marc, sont tous les deux corrects dans leurs commentaires; le besoin d'avoir plus de questions pour vous. Merci pour chacun suggestions et réponses.

61voto

Mark Byers Points 318575

Vous pouvez utiliser Enumerable.Repeat :

 byte[] a = Enumerable.Repeat((byte)10, 100).ToArray();
 

Le premier paramètre est l'élément que vous souhaitez répéter et le second paramètre indique le nombre de répétitions.

Ceci est acceptable pour les petits tableaux, mais vous devriez utiliser la méthode de bouclage si vous avez affaire à de très grands tableaux et que les performances sont un sujet de préoccupation.

55voto

konrad.kruczynski Points 5938

En fait, il est peu connu IL opération appelée Initblk qui fait exactement cela. Donc, nous allons l'utiliser comme une méthode qui ne nécessite pas de "dangereux". Voici la classe helper:

public static class Util
{
    static Util()
    {
        var dynamicMethod = new DynamicMethod("Memset", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
            null, new [] { typeof(IntPtr), typeof(byte), typeof(int) }, typeof(Util), true);

        var generator = dynamicMethod.GetILGenerator();
        generator.Emit(OpCodes.Ldarg_0);
        generator.Emit(OpCodes.Ldarg_1);
        generator.Emit(OpCodes.Ldarg_2);
        generator.Emit(OpCodes.Initblk);
        generator.Emit(OpCodes.Ret);

        MemsetDelegate = (Action<IntPtr, byte, int>)dynamicMethod.CreateDelegate(typeof(Action<IntPtr, byte, int>));
    }

    public static void Memset(byte[] array, byte what, int length)
    {
        var gcHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
        MemsetDelegate(gcHandle.AddrOfPinnedObject(), what, length);
        gcHandle.Free();
    }

    public static void ForMemset(byte[] array, byte what, int length)
    {
        for(var i = 0; i < length; i++)
        {
            array[i] = what;
        }
    }

    private static Action<IntPtr, byte, int> MemsetDelegate;

}

Et qu'est-ce que la performance? Voici mon résultat pour Windows/.NET et Linux/Mono (Pc différents).

Mono/for:     00:00:01.1356610
Mono/initblk: 00:00:00.2385835 

.NET/for:     00:00:01.7463579
.NET/initblk: 00:00:00.5953503

Il est donc utile d'examiner. Notez que le résultat IL ne sera pas vérifiable.

24voto

TowerOfBricks Points 93

Aussi avec un peu de retard (eh bien, tout à fait un peu tard en fait), mais il pourrait servir pour aider les autres utilisateurs de vouloir réinitialiser les tableaux.

Bâtiment sur @Lucero de réponse. Voici une version plus rapide. Il permettra de doubler le nombre d'octets copiés à l'aide de Buffer.BlockCopy chaque itération. Fait intéressant, il surpasse par un facteur de 10 lors de l'utilisation relativement faible des tableaux (1000), mais la différence n'est pas grande pour des matrices plus grandes (1000000), c'est toujours plus rapide. La bonne chose à ce sujet est qu'il fonctionne bien, même aux petits tableaux. Il devient plus rapide que l'approche naïve autour de longueur = 100. Pour un million d'élément de tableau d'octets, il était de 43 fois plus rapide. (testé sur un Intel i7 .Net 2.0)

public static void MemSet(byte[] array, byte value) {
    if (array == null) {
        throw new ArgumentNullException("array");
    }

    int block = 32, index = 0;
    int length = Math.Min(block, array.Length);

    //Fill the initial array
    while (index < length) {
        array[index++] = value;
    }

    length = array.Length;
    while (index < length) {
        Buffer.BlockCopy(array, 0, array, index, Math.Min(block, length-index));
        index += block;
        block *= 2;
    }
}

22voto

Lucero Points 38928

Un peu en retard, mais l'approche suivante pourrait être un bon compromis sans revenir à un code non sécurisé. Fondamentalement, il initialise le début du tableau à l'aide d'une boucle conventionnelle, puis revient à Buffer.BlockCopy() , ce qui devrait être aussi rapide que vous pouvez obtenir en utilisant un appel géré.

 public static void MemSet(byte[] array, byte value) {
  if (array == null) {
    throw new ArgumentNullException("array");
  }
  const int blockSize = 4096; // bigger may be better to a certain extent
  int index = 0;
  int length = Math.Min(blockSize, array.Length);
  while (index < length) {
    array[index++] = value;
  }
  length = array.Length;
  while (index < length) {
    Buffer.BlockCopy(array, 0, array, index, Math.Min(blockSize, length-index));
    index += blockSize;
  }
}
 

6voto

Juliet Points 40758

Si les performances sont absolument essentielles, alors Enumerable.Repeat(n, m).ToArray() sera trop lent pour vos besoins. Vous pourrez peut-être améliorer plus rapidement les performances en utilisant PLINQ ou Task Parallel Library :

 using System.Threading.Tasks;

// ...

byte initialValue = 20;
byte[] data = new byte[size]
Parallel.For(0, size, index => data[index] = initialValue);
 

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