Frage

Ich habe eine einfache Puffer-Manager-Klasse erstellt mit asyncroneous Buchsen verwendet werden. Dies wird gegen Speicherfragmentierung schützen und die Leistung verbessern. Irgendwelche Vorschläge für weitere Verbesserungen oder andere Ansätze?

public class BufferManager
{
    private int[] free;
    private byte[] buffer;
    private readonly int blocksize;

    public BufferManager(int count, int blocksize)
    {
        buffer = new byte[count * blocksize];
        free = new int[count];
        this.blocksize = blocksize;

        for (int i = 0; i < count; i++)
            free[i] = 1;
    }

    public void SetBuffer(SocketAsyncEventArgs args)
    {
        for (int i = 0; i < free.Length; i++)
        {
            if (1 == Interlocked.CompareExchange(ref free[i], 0, 1))
            {
                args.SetBuffer(buffer, i * blocksize, blocksize);
                return;
            }
        }
        args.SetBuffer(new byte[blocksize], 0, blocksize);
    }

    public void FreeBuffer(SocketAsyncEventArgs args)
    {
        int offset = args.Offset;
        byte[] buff = args.Buffer;

        args.SetBuffer(null, 0, 0);

        if (buffer == buff)
            free[offset / blocksize] = 1;
    }
}
War es hilfreich?

Lösung

Bearbeiten :

Die Orignal Antwort unten adressiert eine Codekonstruktion Thema zu enge Kopplung. unter Berücksichtigung jedoch die Lösung, als Ganzes würde ich nur einen großen Puffer und Übergabe Scheiben auf diese Weise unter Verwendung vermeiden. Sie entlarven Sie den Code Überschreitung zu puffern (und wir nennen es „Underrun“ Fragen Puffer). Stattdessen würde ich eine Reihe von Byte-Arrays verwalten jeweils ein diskretes Puffer ist. Offset übergeben ist immer 0 und Größe ist immer die Länge des Puffers. Alle schlechten Code, der zu lesen versucht / Schreib Teile über die Grenzen werden aufgefangen werden.

Original Antwort

Sie haben die Klasse SocketAsyncEventArgs gekoppelt, wo in der Tat alle es eine Funktion benötigt, ist der Puffer zuweisen, ändern Puffersetzen zu: -

public void SetBuffer(Action<byte[], int, int> fnSet)
{
    for (int i = 0; i < free.Length; i++)
    {
        if (1 == Interlocked.CompareExchange(ref free[i], 0, 1))
        {
            fnSet(buffer, i * blocksize, blocksize);
            return;
        }
    }
    fnSet(new byte[blocksize], 0, blocksize);
}

Jetzt können Sie rufen aus dem Konsum Code etwas wie folgt aus: -

myMgr.SetBuffer((buf, offset, size) => myArgs.SetBuffer(buf, offset, size));

Ich bin nicht sicher, dass Typinferenz klug genug ist, um die Arten von buf, offset, size in diesem Fall zu lösen. Wenn nicht Sie werden die Typen in der Argumentliste zu setzen haben: -

myMgr.SetBuffer((byte[] buf, int offset, int size) => myArgs.SetBuffer(buf, offset, size));

Doch jetzt können Sie Ihre Klasse verwendet werden, um einen Puffer für alle Arten von Anforderungen zuweisen, die auch die byte [] verwenden, int, int Muster, das sehr häufig ist.

Natürlich benötigen Sie den kostenlosen Betrieb zu entkoppeln, aber das ist: -

public void FreeBuffer(byte[] buff, int offset)
{
    if (buffer == buff)
        free[offset / blocksize] = 1;
}

Dies erfordert, dass Sie Puffersetzen auf dem EventArgs in raubend Code in dem Fall für SocketAsyncEventArgs nennen. Wenn Sie besorgt sind, dass dieser Ansatz die Unteilbarkeit der Befreiung des Puffers reduziert und Entfernen aus den Steckdosen verwenden, dann Unterklasse dieser eingestellten Puffer-Manager und schließen SocketAsyncEventArgs spezifischen Code in der Unterklasse.

Andere Tipps

Ich habe eine neue Klasse mit einem völlig anderen Ansatz geschaffen.

Ich habe eine Server-Klasse, die Byte-Arrays empfängt. Es wird dann verschiedenen Delegierten aufrufen ihnen die Pufferobjekte, so dass andere Klassen verteilen sie verarbeiten kann. Wenn diese Klassen getan werden müssen sie einen Weg, um die Puffer zurück auf den Stapel zu drücken.

public class SafeBuffer
{
    private static Stack bufferStack;
    private static byte[][] buffers;

    private byte[] buffer;
    private int offset, lenght;

    private SafeBuffer(byte[] buffer)
    {
        this.buffer = buffer;
        offset = 0;
        lenght = buffer.Length;
    }

    public static void Init(int count, int blocksize)
    {
        bufferStack = Stack.Synchronized(new Stack());
        buffers = new byte[count][];

        for (int i = 0; i < buffers.Length; i++)
            buffers[i] = new byte[blocksize];

        for (int i = 0; i < buffers.Length; i++)
            bufferStack.Push(new SafeBuffer(buffers[i]));
    }

    public static SafeBuffer Get()
    {
        return (SafeBuffer)bufferStack.Pop();
    }

    public void Close()
    {
        bufferStack.Push(this);
    }

    public byte[] Buffer
    {
        get
        {
            return buffer;
        }
    }

    public int Offset
    {
        get
        {
            return offset;
        }
        set
        {
            offset = value;
        }
    }

    public int Lenght
    {
        get
        {
            return buffer.Length;
        }
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top