I have a static `ConcurrentDictionary` in a `static` class. In the static constructor of the class, I call a private method via `Task.Run` to indefinitely loop through the dictionary and remove items that have expired, i.e. a significant amount of time has passed since they were added and as such need to be removed (this is determined by by inspecting a property on each `CustomItem` value of each item in the dictionary):

```
public static class ItemsHolder
{
    public static ConcurrentDictionary<Guid, CustomItem> Items = new ConcurrentDictionary<Guid, CustomItem>();

   // ...

    static ItemsHolder
    {
        Task.Run(() => DeleteExpired());
    }

    private static async Task DeleteExpired()
    {
        while (true)
        {
            // check if dictionary is empty and if yes, 
            // await Task.Delay a bit, etc - omitted for brevity

            foreach (var item in Items)
            {
                var guid = item.Key;
                var customItem = item.Value;

                if (customItem.ConditionToRemoveItemFromDictionaryHere)
                {

                    var removeItem = Items.TryRemove(guid, out _);

                    // ...
                }
            }
        }
    }
}

```

In other parts of the code (outside of this class), items are being added to this dictionary and removed based on other conditions. Effectively `DeleteExpired()` is there to clean out items that could not be removed from the dictionary (in other parts of the code, for XYZ reasons)

I see that `DeleteExpired()` keeps popping up in my metrics in tools such as dotTrace in R# as occupying CPU time. I know that iterating through the concurrent dictionary while other threads might be adding/removing is lock-free and should be safe to do, but I'm not sure whether this is the most effective way of doing so. Is there a more effective/efficient way of doing so?