Самый эффективный способ удаления байтов из очереди в C # - PullRequest
2 голосов
/ 09 ноября 2011

У меня есть очередь с некоторыми данными. Если я хочу получить 5 байтов (или столько, сколько доступно, если меньше 5), какой из следующих методов более эффективен, или это не имеет значения?

Вариант 1:

        byte[] ret = null;

        if (this.dataQueue.Count >= numBytes)
        {
            ret = new byte[numBytes];
        }
        else
        {
            ret = new byte[this.dataQueue.Count];
        }

        for (int i = 0; i < ret.Length; i++)
        {
            ret[i] = this.dataQueue.Dequeue();
        }

        return ret;

Вариант 2:

        List<byte> l = new List<byte>();

        try
        {
            for (int i = 0; i < numBytes; i++)
            {
                l.Add(this.dataQueue.Dequeue());
            }
        }
        catch
        {
            System.Diagnostics.Debug.WriteLine(string.Format("Unable to retrieve requested number of bytes from queue. ({0} bytes requested, {1} bytes available)", numBytes, l.Count));
        }

        return l.ToArray();

Заранее спасибо за любой совет.

Ответы [ 3 ]

1 голос
/ 09 ноября 2011

Производительность действительно зависит от вашего сценария, и всегда случается так, что кто-то предупреждает вас, чтобы вы не оптимизировали преждевременно и не находили узкие места, прежде чем предположить, что что-то происходит медленно или что-то подобное, а также существуют предположения с разных сторон, которые могутне верны;Я действительно согласен с предыдущей частью этого, но не люблю делать поспешные выводы и считаю, что части программы демонстрируются медленнее и, следовательно, призываем к необходимости оптимизации такой части.

При этом, во всяком случае, рассмотрим следующую примитивную, не совсем практичную специальную программу (использующую ваши методы с именами Dequeue и TryDequeue здесь, но не в списке):

var data = new byte[4096];
var random = new Random();      
var queue = new Queue<byte>();
var stopWatch = new Stopwatch();

TimeSpan dequeueTimespan, tryDequeueTimespan;

stopWatch.Restart();
for (int i = 0; i < 1000000; i++)
{
    random.NextBytes(data);
    foreach (var item in data)
    {
        queue.Enqueue(item);
    }
    Dequeue(queue, 1024);
    queue.Clear();
}
stopWatch.Stop();
dequeueTimespan = stopWatch.Elapsed;

stopWatch.Restart();
for (int i = 0; i < 1000000; i++)
{
    random.NextBytes(data);
    foreach (var item in data)
    {
        queue.Enqueue(item);
    }
    TryDequeue(queue, 1024);
    queue.Clear();
}
stopWatch.Stop();
tryDequeueTimespan = stopWatch.Elapsed;

Console.WriteLine("Dequeue:    {0}", dequeueTimespan);
Console.WriteLine("TryDequeue: {0}", tryDequeueTimespan);
Console.ReadKey();

Сейчас, если мы выполним более 10000 итераций для каждой, мы получим:

Dequeue:    00:00:12.6178244
TryDequeue: 00:00:13.6747715

И для 1000000 итераций для метода:

Dequeue:    00:02:16.4144764
TryDequeue: 00:02:13.2039597

Конечно, мы делаем прочее работа здесь, но это все относительно;мы также преувеличиваем ваш случай здесь, так как вам требуется всего 5 байтов, так что ...

В первом случае снова 10000 итераций:

Dequeue:    00:00:10.5624014
TryDequeue: 00:00:10.2529997

Я не говорю, что этоидеальны, результаты, но они являются результатами;Но дело в следующем.

То, что снижение производительности между ними незначительно.

Есть также много других факторов, которые следует учитывать в практической среде, которые, разумеется, не стоит пытатьсяПеречислите здесь все различия, о которых вы будете (или узнаете), и вам следует потратить время на то, чтобы привязаться к вашему сценарию.

0 голосов
/ 09 ноября 2011

Не поймите это неправильно, но вы задаете почти невозможный вопрос. Когда дело касается такой небольшой разницы, вам нужно гораздо больше информации, чтобы принять решение в любом случае.

Например, какие оптимизации выполняются и на какой архитектуре будет выполняться. Более того, каково текущее состояние программы и ее поток (ограничен ли объем памяти? Процессор работает на уровне около 100%?) И как насчет кэширования (Applicative \ OS \ hardware).

Этот список неполон, так же далек от него, но он должен пройти точку - если вы работаете с оптимизацией и производительностью в точном масштабе, вам понадобится больше подробностей (не только для нам, но для тех, у кого есть идея для ответа).

Если вы потратите детали своего вопроса, это будет замечательно.

EDIT:

Обратите внимание, что два метода удаляют очередь из очереди одинаковым образом (цикл for с вызовом Dequeue ()), и поэтому не отличаются в этом отношении, а скорее в том, как они собирают элементы, исключенные из Очередь. Если вопрос заключается в том, какой самый быстрый способ сделать это (использовать устаревшие элементы), это просто не собирать их и отправлять их в поток. Если элементы должны быть возвращены, тогда вы возвращаетесь к исходному вопросу, но с подвопросом, который может вам помочь - что вы ожидаете сделать с коллекцией элементов после того, как они сняты с производства.

Надеюсь, это поможет

0 голосов
/ 09 ноября 2011

Первый, потому что он выполняет 1 выделение, тогда как

l.Add(this.dataQueue.Dequeue()) 

необходимо перераспределить пространство, необходимое для списка, несколько раз, если вы не зарезервировали его заранее:

l.Capacity = 5

, чтоне влияет на длину вашего списка, он просто резервирует пространство памяти для элементов (и мы знаем, что у вас их будет максимум 5).

Конечно, также стоит проверить, действительно ли вам нужно иметь байты в очереди и вызыватьОтключайте каждый раз, когда вам нужно получить один байт.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...