سؤال

لقد قمت بإنشاء فئة مدير مؤقت بسيطة لاستخدامها مع المقابس غير المتزامنة.سيؤدي ذلك إلى الحماية من تجزئة الذاكرة وتحسين الأداء.أي اقتراحات لمزيد من التحسينات أو أساليب أخرى؟

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;
    }
}
هل كانت مفيدة؟

المحلول

يحرر:

تتناول الإجابة الأصلية أدناه مشكلة بناء التعليمات البرمجية الخاصة بالاقتران الضيق للغاية.ومع ذلك، وبالنظر إلى الحل ككل، فإنني سأتجنب استخدام مخزن مؤقت كبير واحد فقط وتسليم شرائح منه بهذه الطريقة.أنت تعرض الكود الخاص بك لتجاوز سعة المخزن المؤقت (وهل نطلق عليه مشكلات "تجاوز سعة المخزن المؤقت").بدلاً من ذلك، سأقوم بإدارة مجموعة من صفائف البايت، كل منها عبارة عن مخزن مؤقت منفصل.الإزاحة التي تم تسليمها هي دائمًا 0 والحجم هو دائمًا طول المخزن المؤقت.سيتم اكتشاف أي تعليمات برمجية سيئة تحاول قراءة/كتابة أجزاء خارج الحدود.

الجواب الأصلي

لقد قمت بربط الفئة بـ SwitchAsyncEventArgs حيث كل ما تحتاجه في الواقع هو وظيفة لتعيين المخزن المؤقت، قم بتغيير SetBuffer إلى: -

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

الآن يمكنك الاتصال من استهلاك الكود بشيء مثل هذا: -

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

لست متأكدًا من أن استنتاج النوع ذكي بما يكفي لحل أنواع buf, offset, size في هذه الحالة.إذا لم يكن الأمر كذلك فسيتعين عليك وضع الأنواع في قائمة الوسائط: -

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

ولكن الآن يمكن استخدام فصلك لتخصيص مخزن مؤقت لجميع أنواع المتطلبات التي تستخدم أيضًا نمط البايت []، int، int وهو أمر شائع جدًا.

بالطبع تحتاج إلى فصل العملية المجانية ولكن هذا: -

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

يتطلب هذا منك الاتصال بـ SetBuffer على EventArgs لاستهلاك التعليمات البرمجية في حالة SocketAsyncEventArgs.إذا كنت قلقًا من أن هذا الأسلوب يقلل من ذرية تحرير المخزن المؤقت وإزالته من استخدام المقابس، فقم بتصنيف مدير المخزن المؤقت المعدل هذا إلى فئة فرعية وقم بتضمينه SocketAsyncEventArgs رمز محدد في الفئة الفرعية.

نصائح أخرى

ولقد خلق طبقة جديدة مع اتباع نهج مختلف تماما.

ولدي فئة خادم الذي يتلقى صفائف بايت. وسوف ثم استدعاء مندوبي مختلف تسليمهم الكائنات عازلة بحيث الطبقات الأخرى يمكن معالجتها. عندما يتم الانتهاء من تلك الطبقات فإنها بحاجة إلى وسيلة لدفع مخازن يعود إلى المكدس.

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;
        }
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top