2017-10-25 1 views
1

Ich erstellte zufällige Byte-Arrays, um einige Transportschicht zu testen. Ich benutzen Daten wie dieseSo erstellen Sie zufällige Daten effizient

public byte[] Read(Data data) { 
    var rnd = new Random(); 
    int size = data.ChunkSize; 

    byte[] array = new byte[size]; 
    rnd.NextBytes(array); 
    return array; 
} 

erstellt transportieren Da Read() oft genannt wird, und einen neuen Byte-Array jedes Mal zu schaffen und es mit zufälligen Daten füllen langsam sein könnte, wollte ich mit einer Lösung kommen, die verwendet nicht in jedem Anruf.

Also ich kam mit einer Klasse, die eine statische zufällige Array enthält und liest daraus. Wenn es bis zum Ende des Arrays kommt, wird es von der wieder beginn beginnen:

public class MyBuffer 
{ 
private static readonly Random SRandom = new Random(); 

private readonly byte[] buffer = new byte[5000000]; // 5mb array with random data to read from 
private int currentStart; 

public MyBuffer() 
{ 
    SRandom.NextBytes(buffer); 
} 

public IEnumerable<byte> Latest(int amountOfBytes) 
{ 
    return FetchItems(amountOfBytes).ToArray(); 
} 

private IEnumerable<byte> FetchItems(int amountOfBytes) 
{ 
    IEnumerable<byte> fetchedItems = Enumerable.Empty<byte>(); 
    int total = 0; 

    while (total < amountOfBytes) 
    { 
    int min = Math.Min(amountOfBytes, buffer.Length - currentStart); 
    fetchedItems = fetchedItems.Concat(FetchItems(currentStart, min)); 

    total += min; 
    currentStart += min; 
    currentStart = currentStart % buffer.Length; 
    } 

    return fetchedItems; 
} 
private IEnumerable<byte> FetchItems(int start, int end) 
{ 
    for (int i = start; i < end; i++) 
    { 
    yield return buffer[i]; 
    } 
} 
} 

und der Angerufene-Code sieht wie folgt aus:

private static readonly MyBuffer SBuffer = new MyBuffer(); 
private static byte[] array = new byte[0]; 

public byte[] Read(Data data) { 

    int size = data.ChunkSize; 

    if (array.Length != size) 
    { 
    array = new byte[size]; 
    } 

    Array.Copy(SBuffer.Latest(size).ToArray(), array, size); 
    return array; 
} 

Aber dies stellt sich heraus, noch langsamer zu sein (Art und Weise langsamer) als mein erster Versuch, und ich kann nicht wirklich sehen warum. Jeder kann mir sagen, wo mein Code ineffizient ist oder eine andere effiziente Lösung für mein Problem finden?

Dank

+0

Haben Sie eigentlich Performance-Probleme mit gelegentlichen 'NextBytes' haben? Wenn ja, wie viel schneller muss es sein? Verschieben Sie auch Ihre Instanziierung "Random" außerhalb der Methode. – FCin

+0

@FCin Zur Verdeutlichung: Ich erstelle diese zufälligen Daten auf einem Server und sende sie über Ethernet an den Client. Ich möchte unsere Transportschicht benchmarken und sicherstellen, dass das Erstellen und Füllen des Arrays nicht mein Engpass bei der Datenübertragung ist. – user3292642

+0

Erstellen von zufälligen Bytes ist extrem schnell ... Viel schneller als das Kopieren von Brocken von Arrays herum und versuchen, sie zu concattieren. –

Antwort

0

Wenn Sie über die Qualität der Zufallsdaten nicht zu viel Sie Ihre eigene RNG schreiben können, die einfache lineare Kongruenz Generation verwendet:

public static int FillWithRandomData(int seed, byte[] array) 
{ 
    unchecked 
    { 
     int n = seed * 134775813 + 1; 

     for (int i = 0; i < array.Length; ++i) 
     { 
      array[i] = (byte) n; 
      n = 2147483629 * n + 2147483587; 
     } 

     return n; 
    } 
} 

Diese ziemlich schnell ist, obwohl es hat keine sehr lange Zeit - aber ich denke, es würde für Ihre Zwecke ausreichen.

Wenn Sie dies Zeit, stellen Sie sicher, dass Sie einen Release-Build nicht ein Debug-Build.

Es ist etwa sieben mal schneller als mit Random.NextBytes(), wenn ich es zeitlich.

Sie können Random verwenden, um einen Startwert zu erstellen, wenn Sie ihn aufrufen, oder einfach den Rückgabewert des vorherigen Aufrufs übergeben.

Hier ist mein vollständiger Test-App:

using System; 
using System.Diagnostics; 

namespace Demo 
{ 
    public class Program 
    { 
     static void Main() 
     { 
      byte[] data = new byte[90 * 1024 * 1024]; 

      Stopwatch sw = Stopwatch.StartNew(); 

      int seed = (int) DateTime.Now.Ticks; 

      for (int i = 0; i < 10; ++i) 
       seed = FillWithRandomData(seed, data); 

      Console.WriteLine(sw.Elapsed); 
     } 

     public static int FillWithRandomData(int seed, byte[] array) 
     { 
      unchecked 
      { 
       int n = seed * 134775813 + 1; 

       for (int i = 0; i < array.Length; ++i) 
       { 
        array[i] = (byte) n; 
        n = 2147483629 * n + 2147483587; 
       } 

       return n; 
      } 
     } 
    } 
} 
Verwandte Themen