Soenneker.Sets.Concurrent.SlidingWindow
4.0.9
Prefix Reserved
dotnet add package Soenneker.Sets.Concurrent.SlidingWindow --version 4.0.9
NuGet\Install-Package Soenneker.Sets.Concurrent.SlidingWindow -Version 4.0.9
<PackageReference Include="Soenneker.Sets.Concurrent.SlidingWindow" Version="4.0.9" />
<PackageVersion Include="Soenneker.Sets.Concurrent.SlidingWindow" Version="4.0.9" />
<PackageReference Include="Soenneker.Sets.Concurrent.SlidingWindow" />
paket add Soenneker.Sets.Concurrent.SlidingWindow --version 4.0.9
#r "nuget: Soenneker.Sets.Concurrent.SlidingWindow, 4.0.9"
#:package Soenneker.Sets.Concurrent.SlidingWindow@4.0.9
#addin nuget:?package=Soenneker.Sets.Concurrent.SlidingWindow&version=4.0.9
#tool nuget:?package=Soenneker.Sets.Concurrent.SlidingWindow&version=4.0.9
Soenneker.Sets.Concurrent.SlidingWindow
A high-throughput, thread-safe set whose bucketed entries automatically expire after a fixed time window.
Soenneker.Sets.Concurrent.SlidingWindow provides a concurrent sliding-window set for .NET.
Items added to the set automatically expire after a configurable time window without requiring manual cleanup.
The implementation is optimized for high-concurrency workloads and avoids expensive per-item timers by using a bucketed time-slice rotation system.
This makes it ideal for deduplication, rate limiting, and recent activity tracking.
Installation
dotnet add package Soenneker.Sets.Concurrent.SlidingWindow
Why this library exists
Many systems need to track items that should only exist for a limited period of time, such as:
- recently processed messages
- request IDs
- phone numbers
- event IDs
- authentication tokens
Traditional options have downsides:
| Approach | Problem |
|---|---|
ConcurrentDictionary |
Requires manual expiration |
MemoryCache |
Heavy and feature-rich for simple tracking |
| Per-item timers | Extremely expensive at scale |
| Background cleanup scans | High CPU cost |
SlidingWindowConcurrentSet solves this by using bucketed time slices where items automatically expire when their time window passes.
Key Features
✔ High-throughput concurrent operations
✔ Automatic expiration of entries
✔ Sliding window time-based retention
✔ Lock-minimized design
✔ Low allocation footprint
✔ No per-item timers
✔ Safe for heavy multi-threaded workloads
Example
using Soenneker.Sets.Concurrent.SlidingWindow;
var set = new SlidingWindowConcurrentSet<string>(
window: TimeSpan.FromMinutes(5),
rotationInterval: TimeSpan.FromSeconds(30)
);
set.TryAdd("alpha");
bool exists = set.Contains("alpha");
await Task.Delay(TimeSpan.FromMinutes(6));
bool expired = set.Contains("alpha"); // false
Configuration
var set = new SlidingWindowConcurrentSet<string>(
window: TimeSpan.FromMinutes(10),
rotationInterval: TimeSpan.FromSeconds(15)
);
| Parameter | Description |
|---|---|
window |
Total time items remain valid |
rotationInterval |
Time slice size used for bucket rotation |
capacityHint |
Initial capacity hint for the internal dictionary |
comparer |
Optional equality comparer |
The window is internally divided into time buckets:
window / rotationInterval = number of buckets
Example:
window = 5 minutes
rotationInterval = 30 seconds
bucket count = 10
Each rotation advances the window and expires the oldest bucket.
How it works
The set maintains:
- a ConcurrentDictionary for fast lookup
- a ring buffer of queues representing time buckets
When an item is added:
- It is assigned the current time bucket
- The value is queued in that bucket
- The dictionary records the bucket index
A background rotation process periodically:
- Advances the active bucket
- Processes the expired bucket
- Removes items whose last activity falls outside the sliding window
This avoids scanning the entire collection.
Performance Characteristics
| Operation | Complexity |
|---|---|
TryAdd |
O(1) |
Contains |
O(1) |
TryRemove |
O(1) |
| Expiration | O(n) only for items in expiring bucket |
The design ensures:
- predictable memory usage
- minimal locking
- bounded cleanup work
Thread Safety
All operations are thread-safe.
The set is designed for high-concurrency environments and does not require external synchronization.
Disposal
The set uses an internal rotation task driven by PeriodicTimer.
When the set is no longer needed, it should be disposed:
set.Dispose();
or
await set.DisposeAsync();
This stops the internal rotation loop.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Soenneker.Atomics.Longs (>= 4.0.5)
- Soenneker.Atomics.ValueBools (>= 4.0.12)
- Soenneker.Extensions.Task (>= 4.0.112)
- Soenneker.Extensions.ValueTask (>= 4.0.105)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Soenneker.Sets.Concurrent.SlidingWindow:
| Package | Downloads |
|---|---|
|
Soenneker.Deduplication.SlidingWindow
High-performance sliding-window deduplication for .NET. |
GitHub repositories
This package is not used by any popular GitHub repositories.