ZeroAlloc.AsyncEvents
1.0.0
dotnet add package ZeroAlloc.AsyncEvents --version 1.0.0
NuGet\Install-Package ZeroAlloc.AsyncEvents -Version 1.0.0
<PackageReference Include="ZeroAlloc.AsyncEvents" Version="1.0.0" />
<PackageVersion Include="ZeroAlloc.AsyncEvents" Version="1.0.0" />
<PackageReference Include="ZeroAlloc.AsyncEvents" />
paket add ZeroAlloc.AsyncEvents --version 1.0.0
#r "nuget: ZeroAlloc.AsyncEvents, 1.0.0"
#:package ZeroAlloc.AsyncEvents@1.0.0
#addin nuget:?package=ZeroAlloc.AsyncEvents&version=1.0.0
#tool nuget:?package=ZeroAlloc.AsyncEvents&version=1.0.0
ZeroAlloc.AsyncEvents
Zero-allocation async event handler structs for .NET. Lock-free registration, ValueTask invocation, ArrayPool parallel dispatch.
Key Characteristics
- Lock-free registration — CAS-loop register/unregister, no locks
- ValueTask throughout — no
Taskallocations on hot paths - ArrayPool parallel dispatch — rented array for fan-out, returned immediately after
WhenAll - Multi-target —
netstandard2.0,netstandard2.1,net8.0,net10.0 - AOT compatible
Performance
10 handlers registered, invoked once. Compared against EventHandler<T> (sync multicast, baseline) and naive async (Func<string, Task> + Task.WhenAll). BenchmarkDotNet v0.14.0, .NET 9, X64 RyuJIT AVX2.
| Method | Mean | Error | StdDev | Ratio | Allocated |
|---|---|---|---|---|---|
| Sync_MulticastDelegate_10Handlers | 22.96 ns | 0.926 ns | 2.597 ns | 1.01 | — |
| NaiveAsync_TaskWhenAll_10Handlers | 203.48 ns | 4.111 ns | 7.307 ns | 8.96x | 280 B |
| ZeroAlloc_Parallel_10Handlers | 70.10 ns | 1.446 ns | 4.103 ns | 3.09x | 136 B |
| ZeroAlloc_Sequential_10Handlers | 16.10 ns | 0.655 ns | 1.857 ns | 0.71x | — |
ZeroAlloc sequential mode is 30% faster than a sync multicast delegate with zero allocations. ZeroAlloc parallel mode is 3× faster than naive async with 51% less memory.
Installation
dotnet add package ZeroAlloc.AsyncEvents
Quick Start
// Declare
private AsyncEventHandler<OrderPlacedArgs> _orderPlaced = new(InvokeMode.Parallel);
// Expose as a C# event with explicit add/remove
public event AsyncEvent<OrderPlacedArgs> OrderPlaced
{
add => _orderPlaced.Register(value);
remove => _orderPlaced.Unregister(value);
}
// Invoke
await _orderPlaced.InvokeAsync(new OrderPlacedArgs(orderId), cancellationToken);
Async INotify* Interfaces
Async INotify* interfaces and event args are provided by ZeroAlloc.Notify, which builds on this package.
Design Philosophy
AsyncEventHandler<TArgs> is a struct wrapping a State reference — copy semantics are intentional and match how event fields work in C#. Use it as a private field and expose Register/Unregister methods, or use the +=/-= operators directly.
CancellationToken is threaded through every call site — handlers opt into cooperative cancellation at the delegate boundary. Sequential mode respects cancellation between handler invocations; parallel mode checks before dispatch.
See docs/ for full documentation.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Buffers (>= 4.5.1)
- System.Threading.Tasks.Extensions (>= 4.5.4)
-
.NETStandard 2.1
- No dependencies.
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on ZeroAlloc.AsyncEvents:
| Package | Downloads |
|---|---|
|
AdoNet.Async.DataSet
Async DataSet and DataTable for ADO.NET (System.Data). Includes AsyncDataTable, AsyncDataSet, and AsyncDataAdapter. |
|
|
ZeroAlloc.Notify
Source-generated async INotifyPropertyChanged, INotifyPropertyChanging, INotifyCollectionChanged and INotifyDataErrorInfo for .NET. Zero-allocation, ValueTask-based, no fire-and-forget. |
GitHub repositories
This package is not used by any popular GitHub repositories.