Pergunta

Eu criei uma classe gerenciador de buffer simples de ser usado com soquetes asyncroneous. Isto irá proteger contra a fragmentação da memória e melhorar o desempenho. Todas as sugestões para melhorias ou outras abordagens?

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;
    }
}
Foi útil?

Solução

Editar :

A resposta orignal abaixo aborda um problema de construção código de acoplamento excessivamente apertado. No entanto, considerando a solução como toda a gostaria de evitar o uso de apenas um grande buffer e entrega fatias de la desta forma. Você expor o seu código para saturação de buffer (e vamos chamá-lo de tampão "contra o encaixe" questões). Em vez disso eu gerir um conjunto de matrizes de bytes sendo cada um tampão discreta. Deslocamento entregue é sempre 0 e tamanho é sempre o comprimento do tampão. Qualquer código ruim que tentativas de ler / escrever peças para além das fronteiras será pego.

resposta Original

Você acoplada a classe para SocketAsyncEventArgs onde de fato tudo o que precisa é uma função para atribuir o buffer, a mudança SetBuffer a: -

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

Agora você pode chamar de consumir código algo como isto: -

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

Eu não tenho certeza de que tipo de inferência é bastante inteligente para resolver os tipos de buf, offset, size neste caso. Se não você terá que colocar os tipos na lista de argumentos: -

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

No entanto, agora a sua classe pode ser usada para alocar um buffer para todos os tipos de requisitos que também usam o byte [], int, int padrão que é muito comum.

Claro que você precisa para desacoplar a operação livre para, mas isso é: -

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

Isso requer que você chamar SetBuffer nas EventArgs em consumir código no caso de SocketAsyncEventArgs. Se você está preocupado que esta abordagem reduz a atomicidade de libertar o buffer e retirando-o das tomadas de usar, em seguida, sub-classe este gerente e tampão ajustado incluir código específico SocketAsyncEventArgs na sub-classe.

Outras dicas

Eu criei uma nova classe com uma abordagem completamente diferente.

Eu tenho uma classe servidor que recebe matrizes de bytes. Ele vai então invocar diferentes delegados entregando-o tampão de objectos de modo a que outras classes podem processá-los. Quando essas classes são feitos eles precisam de uma maneira de empurrar os buffers de volta à pilha.

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;
        }
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top