Удаление элементов из ConcurrentDictionary - PullRequest
0 голосов
/ 11 октября 2018

У меня есть объекты Queue of Sky, где мой процесс подбирает каждый из них и выполняет его.Если нужны результаты, они помещаются в ConcurrentDictionary для извлечения с использованием GUID.Небесные объекты добавляются и выполняются из очереди каждые несколько миллисекунд, и этот процесс будет выполняться часами.При извлечении результатов из ConcurrentDictionary выполняется попытка удаления и удаления объектов, но некоторые из них могут быть не извлечены, поскольку они не нужны.Я реализовал идею не создавать результаты, если они не нужны.На всякий случай я добавил дату создания UTC для каждого небесного объекта.

Я хочу создать процесс очистки, который будет запускаться каждые несколько минут, чтобы найти любое время UTC старше x минут и удалить их.Как я понимаю ConcurrentDictionary, у меня не должно возникнуть никаких проблем, просто перебирая коллекцию и просто удаляя их, но у меня есть несколько вопросов, прежде чем писать процедуру очистки.

Должен ли я запустить процесс очистки вотдельная асинхронная задача?Будет ли моя итерация или удаление причины препятствовать добавлению каких-либо результатов в ConcurrentDictionary, например, проблемы блокирования?

Итак, я добавил второй ConcurrentDictionary.Когда я добавляю результаты в первый словарь, я также добавляю guid и дату UTC ко второму.Приведенный ниже код повторяет второй и все просроченные элементы, которые он находит, удаляется из первого.Я еще не проверял это, поэтому я не уверен, что смогу удалить из секунд, пока я перебираю словарь.

    /// <summary>
    /// Use to clean up an sky results objects that might be left in the results dictionary
    /// This compares the now UTC date to the object created date plus the seconds parameter
    /// </summary>
    /// <param name="seconds"></param>
    public static void CleanSkyResultDictionary(double seconds)
    {
        foreach (var skyresult in SkyCleanupDictionary)
        {
            if (skyresult.Value.AddSeconds(seconds) <= DateTime.UtcNow) continue;
            SkyResultDictionary.TryRemove(skyresult.Key, out _);
            SkyCleanupDictionary.TryRemove(skyresult.Key, out _);
        }
    }

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

1.Данные

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

Предлагаю хранить отметку в том же словаре.Один из способов сделать это:

class ToStore {
 //Constructor here, or add public sets

 public YourClass Data {get;}
 public DateTime AddedAtUtc {get;} 
 //I would suggest using NodaTime's Instant, but that's out of scope for this question.
}

public void Add(YourClass data )
{
    if (data == null)
    {
       throw new ArgumentNullException(nameof(data ));
    }

    var frame = new ToStore {
        Data = data,
        AddedUtc = DateTime.UtcNow 
    }

    dict.TryAdd(frame.TimestampUtc, frame);
    OnAdd(); // fire and forget
}

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

2.Очистка

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

    public void Add(YourOtherClass data )
    {
        (...)
        OnAdd(); // fire and forget
    }

    private void OnAdd()
    {
        Task.Run(() =>
        {
            CleanUp();
        }).ConfigureAwait(false);
    }

Cleanup:

        foreach (var kvp in dict.Where(IsStale))
        {
            // Please note that by now the frame may have been already
            // removed by another thread.
            dict.TryRemove(kvp.Key, out var ignored);
        }

где IsStale возвращает true, если кадр достаточно старый, чтобы его можно было удалить.

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

0 голосов
/ 11 октября 2018

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

...