У меня есть готовая реализации (thread safe) когда надо найти объекты с временем жизни среди миллионов с минимальным расходованием CPU.
Nuget
https://www.nuget.org/packages/ShtrihM.Wattle3.Con...
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using ShtrihM.Wattle3.Containers.DateTimeCollections;
using ShtrihM.Wattle3.DomainObjects;
using ShtrihM.Wattle3.DomainObjects.Common;
namespace ShtrihM.Wattle3.Tests.DomainObjects.TestsContainers;
[TestFixture]
public class TestsDateTimeEntries
{
public class DateTimeEntry : IDateTimeEntry
{
public static long CountCanTake;
public DateTimeEntry(DateTime point, long identity)
{
Point = point;
Identity = identity;
}
public bool CanTake(DateTime takePoint)
{
Interlocked.Increment(ref CountCanTake);
var result = Point <= takePoint;
return result;
}
public DateTime Point { get; }
public long Identity { get; }
}
[Test]
[TestCase(1_000_000, 1)]
[TestCase(1_000_000, 2)]
[TestCase(1_000_000, 1_0)]
[TestCase(1_000_000, 1_00)]
[TestCase(1_000_000, 1_000)]
[TestCase(1_000_000, 1_00_000)]
public void Test_Metrics(int size, int factor)
{
var instance =
new DateTimeEntries<DateTimeEntry>(
new LocksPoolAsync<long>(
Guid.NewGuid(),
"Test",
"Test",
new TimeService()));
var entries = new ConcurrentDictionary<long, DateTimeEntry>(Environment.ProcessorCount, size);
var startPoint = new DateTime(2023, 5, 5, 5, 5, 5);
Parallel.For(0, size,
i =>
{
var point = startPoint.AddMinutes(i);
var temp = new DateTimeEntry(point, i);
Assert.IsTrue(instance.TryAdd(point, temp));
Assert.IsTrue(entries.TryAdd(temp.Identity, temp));
});
// ReSharper disable once PossibleLossOfFraction
var point = startPoint.AddMinutes(size / factor - 1);
Console.WriteLine($"Элементов : {size}");
Console.WriteLine($"Выбор первых : {size / factor}");
Console.WriteLine();
Console.WriteLine("DateTimeEntries :");
var sw = Stopwatch.StartNew();
DateTimeEntry.CountCanTake = 0;
var items = instance.Take(point, false);
sw.Stop();
Assert.AreEqual(size / factor, items.Count);
Console.WriteLine($"Count = {items.Count}");
Console.WriteLine($"Time = {sw.Elapsed}");
Console.WriteLine($"CanTake = {DateTimeEntry.CountCanTake}");
Console.WriteLine();
Console.WriteLine("ConcurrentDictionary + Parallel.ForEach :");
sw = Stopwatch.StartNew();
DateTimeEntry.CountCanTake = 0;
items = new List<DateTimeEntry>(size);
Parallel.ForEach(entries,
@entry =>
{
if (false == @entry.Value.CanTake(point))
{
return;
}
lock (items)
{
items.Add(@entry.Value);
}
});
sw.Stop();
Assert.AreEqual(size / factor, items.Count);
Console.WriteLine($"Count = {items.Count}");
Console.WriteLine($"Time = {sw.Elapsed}");
Console.WriteLine($"CanTake = {DateTimeEntry.CountCanTake}");
}
}