В C# BufferBlock, что хранит уникальные предметы


В нашем приложении мы наблюдаем изменения файла с помощью .Чистая FileSystemWatcher. После каждого изменения файла мы обрабатываем новый контент асинхронно. Для того, чтобы сделать все, гибкой и гладкой, мы использовали ТПЛ BufferBlock<T>

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

Так что, в принципе, мы хотим в следующем:

  1. Легкий в использовании коллекция, которая работает аналогично очереди и предоставляет возможность ждать новые предметы без каких-либо while (true) петли.
  2. Потокобезопасность.
  3. Детали внутри должны быть уникальными.

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

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;

public class UniqueBufferBlock
{
    private readonly BufferBlock<string> _buffer = new BufferBlock<string>();
    private readonly HashSet<string> _hashSet = new HashSet<string>();
    private readonly object _locker = new object();

    public void Post(string value)
    {
        lock (_locker)
        {
            if (_hashSet.Add(value))
            {
                _buffer.Post(value);
            }
        }
    }

    public string Recieve()
    {
        lock (_locker)
        {
            var value = _buffer.Receive();
            _hashSet.Remove(value);
            return value;
        }
    }

    public Task<bool> OutputAvailable(CancellationToken cancelToken)
    {
        return _buffer.OutputAvailableAsync(cancelToken);
    }
}

Типичное использование:

fileWatcher.FileChanged += (_, fileName) => uniqueBufferBlock.Post(fileName);

// ...

while (await uniqueBufferBlock.OutputAvailable(cancelToken))
{
    var fileName = uniqueBufferBlock.Receive();
    await ProcessFile(fileName, cancelToken);
}

Какие недостатки мы можем столкнуться с ним и что можно улучшить?



340
2
задан 15 февраля 2018 в 03:02 Источник Поделиться
Комментарии
1 ответ

Если вы стремитесь к поцелую на уровне обслуживания, это выглядит как разумное решение, хотя есть некоторые незначительные детали, которые ИМО может быть улучшена.


public class UniqueBufferBlock
{
private readonly BufferBlock<string> _buffer = new BufferBlock<string>();
private readonly HashSet<string> _hashSet = new HashSet<string>();

Почему не genericise класс?


    public string Recieve()

Исправить орфографию. Неправильно имена являются одним из Бэйнс программиста техническое обслуживание.


    public Task<bool> OutputAvailable(CancellationToken cancelToken)

Следуйте конвенциям: это должен иметь имя, заканчивающееся Asyncкак метод обертывания.


Есть несколько других направлений, которые стоит рассматривать. Один на полную катушку и реализовать IPropagatorBlock. Другой похудеть в зависимости от удаления _buffer и реализации OutputAvailableAsync С TaskCompletionSource. Как бы сделать реализацию UniqueBufferBlock более неудобный, и разумно решили не идти в любом направлении.


ЗЫ по английскому языку педантичность: отличие - это лучший выбор слов, Чем уникальный. Возможно, дедуплицированного будет еще лучше в этом контексте.

4
ответ дан 15 февраля 2018 в 04:02 Источник Поделиться