-
Notifications
You must be signed in to change notification settings - Fork 13
Main #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Main #7
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# Async Runtimes Benchmarks 2025 | ||
|
||
## Benchmark Evolution and Methodology | ||
|
||
### Purpose | ||
|
||
This benchmark aims to measure the memory footprint and performance characteristics of concurrent tasks across different programming language runtimes in 2025. | ||
|
||
### Benchmark Specification | ||
|
||
- Spawn N concurrent tasks (controlled by command-line argument) | ||
- Default task count: 100,000 | ||
- Each task waits for 10 seconds | ||
- Program exits when all tasks complete | ||
|
||
## Improvements in 2025 Benchmark | ||
|
||
### Standardization Efforts | ||
|
||
1. **Consistent Task Implementation** | ||
- Explicit task creation mechanism - 2024 previous implementations vary slightly in how they create and manage tasks. We should standardize. | ||
- Standardized 10-second wait | ||
- Detailed task result tracking | ||
- Comprehensive error handling | ||
- Detailed performance tracking | ||
|
||
2. **Language-Specific Enhancements** | ||
- Python (asyncio): | ||
- Explicit task creation with `asyncio.create_task()` | ||
- Comprehensive error handling | ||
- Detailed task result tracking | ||
|
||
- Node.js: | ||
- Promise-based task creation | ||
- Error handling with `Promise.allSettled()` | ||
- Detailed task duration tracking | ||
|
||
- Go: | ||
- Context-based timeout management | ||
- Structured goroutine approach | ||
- Error tracking and reporting | ||
|
||
- Rust (Tokio): | ||
- Detailed task tracking | ||
- Cancellation support | ||
- Comprehensive error handling | ||
|
||
- Kotlin (Coroutines): | ||
- TaskResult data class for comprehensive result tracking | ||
- Kotlin coroutines for concurrent task management | ||
- Detailed timing with Instant and Duration | ||
- coroutineScope for structured concurrency | ||
- awaitAll() for comprehensive task completion | ||
- Flexible task count with default of 100,000 | ||
- Detailed result printing with task ID and duration | ||
|
||
- C# (.NET Tasks): | ||
- Introduced a record TaskResult for structured result tracking | ||
- Used Task.Run() for concurrent task creation | ||
- Implemented detailed timing with DateTime and TimeSpan | ||
- Used ConcurrentBag for thread-safe result collection | ||
- Comprehensive error handling | ||
- Flexible task count with default of 100,000 | ||
- Optional result printing with task details | ||
|
||
- Elixir (Processes): | ||
- Created a custom struct for task result tracking | ||
- Used Elixir's lightweight processes for concurrency | ||
- Implemented detailed timing with system time | ||
- Used spawn_link for process creation | ||
- Message passing for result collection | ||
- Flexible task count with default of 100,000 | ||
- Optional result printing with task ID and duration | ||
|
||
### Benchmarking Recommendations | ||
|
||
## Overarching Recommendations: | ||
|
||
- Standardize memory tracking across languages | ||
- Add detailed logging and tracing | ||
- Implement consistent performance metrics | ||
- Create a unified result collection and reporting mechanism | ||
- Add configuration for different benchmark scenarios | ||
|
||
1. **Consistent Environment** | ||
- Use identical hardware | ||
- Standardized OS and runtime versions | ||
- Minimal background processes | ||
|
||
2. **Metrics Collection** | ||
- Memory usage | ||
- CPU utilization | ||
- Task creation overhead | ||
- Total execution time | ||
- Garbage collection impact | ||
|
||
### Methodology Notes | ||
|
||
- Multiple iterations for statistical significance | ||
- Warm-up runs to stabilize runtime environments | ||
- Detailed logging of task performance | ||
|
||
### Future Improvements | ||
|
||
- Implement similar benchmarking approach | ||
- Add more language runtimes | ||
- Implement more sophisticated memory profiling | ||
- Create visualization tools for result comparison | ||
|
||
## Conclusion | ||
|
||
This benchmark provides insights into the concurrent task handling capabilities of different language runtimes, highlighting the evolving landscape of asynchronous programming in 2025. |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,10 +1,158 @@ | ||||||||||||||||||||||||||||||||||||||||||
int numTasks = int.Parse(args[0]); | ||||||||||||||||||||||||||||||||||||||||||
using System; | ||||||||||||||||||||||||||||||||||||||||||
using System.Collections.Concurrent; | ||||||||||||||||||||||||||||||||||||||||||
using System.Diagnostics; | ||||||||||||||||||||||||||||||||||||||||||
using System.Runtime.InteropServices; | ||||||||||||||||||||||||||||||||||||||||||
using System.Threading.Tasks; | ||||||||||||||||||||||||||||||||||||||||||
using Microsoft.Extensions.Logging; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
List<Task> tasks = new List<Task>(numTasks); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
for (int i = 0; i < numTasks; i++) | ||||||||||||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||||||||||||
/// Advanced .NET 9 Async Tasks Benchmark | ||||||||||||||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||||||||||||||
/// Key Features: | ||||||||||||||||||||||||||||||||||||||||||
/// - Leveraging .NET 9 performance improvements | ||||||||||||||||||||||||||||||||||||||||||
/// - Native AOT compilation support | ||||||||||||||||||||||||||||||||||||||||||
/// - Advanced memory profiling | ||||||||||||||||||||||||||||||||||||||||||
/// - Detailed logging | ||||||||||||||||||||||||||||||||||||||||||
/// - Configurable concurrency | ||||||||||||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||||||||||||
public class AsyncTasksBenchmark | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
tasks.Add(Task.Delay(TimeSpan.FromSeconds(10))); | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||||||||||||
/// Detailed task performance metrics with .NET 9 enhancements | ||||||||||||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||||||||||||
public record TaskMetrics( | ||||||||||||||||||||||||||||||||||||||||||
int TaskId, | ||||||||||||||||||||||||||||||||||||||||||
DateTime StartTime, | ||||||||||||||||||||||||||||||||||||||||||
DateTime EndTime, | ||||||||||||||||||||||||||||||||||||||||||
long StartMemory, | ||||||||||||||||||||||||||||||||||||||||||
long EndMemory) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||||||||||||
/// Calculate task duration using .NET 9 time abstractions | ||||||||||||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||||||||||||
public TimeSpan Duration => EndTime - StartTime; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||||||||||||
/// Calculate memory change with improved precision | ||||||||||||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||||||||||||
public long MemoryChange => EndMemory - StartMemory; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||||||||||||
/// Advanced memory profiler optimized for .NET 9 | ||||||||||||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||||||||||||
private static class MemoryProfiler | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||||||||||||
/// Get current process memory usage with .NET 9 improvements | ||||||||||||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||||||||||||
public static long GetMemoryUsage() | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
// Leverage .NET 9 cross-platform memory tracking | ||||||||||||||||||||||||||||||||||||||||||
return GC.GetTotalMemory(false); | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||||||||||||
/// Perform an asynchronous task with comprehensive tracking | ||||||||||||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||||||||||||
private static async Task<TaskMetrics> PerformTaskAsync( | ||||||||||||||||||||||||||||||||||||||||||
int taskId, | ||||||||||||||||||||||||||||||||||||||||||
ILogger logger) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
// Leverage .NET 9's improved task tracking | ||||||||||||||||||||||||||||||||||||||||||
var startTime = DateTime.UtcNow; | ||||||||||||||||||||||||||||||||||||||||||
var startMemory = MemoryProfiler.GetMemoryUsage(); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
try | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
// Simulate 10-second task with improved delay mechanism | ||||||||||||||||||||||||||||||||||||||||||
await Task.Delay(TimeSpan.FromSeconds(10)); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
var endTime = DateTime.UtcNow; | ||||||||||||||||||||||||||||||||||||||||||
var endMemory = MemoryProfiler.GetMemoryUsage(); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
// Advanced logging with structured logging | ||||||||||||||||||||||||||||||||||||||||||
logger.LogInformation( | ||||||||||||||||||||||||||||||||||||||||||
"Task {TaskId} completed. Duration: {Duration}ms, Memory Change: {MemoryChange} bytes", | ||||||||||||||||||||||||||||||||||||||||||
taskId, | ||||||||||||||||||||||||||||||||||||||||||
(endTime - startTime).TotalMilliseconds, | ||||||||||||||||||||||||||||||||||||||||||
endMemory - startMemory | ||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
return new TaskMetrics( | ||||||||||||||||||||||||||||||||||||||||||
TaskId: taskId, | ||||||||||||||||||||||||||||||||||||||||||
StartTime: startTime, | ||||||||||||||||||||||||||||||||||||||||||
EndTime: endTime, | ||||||||||||||||||||||||||||||||||||||||||
StartMemory: startMemory, | ||||||||||||||||||||||||||||||||||||||||||
EndMemory: endMemory | ||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
catch (Exception ex) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
// Enhanced error handling with .NET 9 logging | ||||||||||||||||||||||||||||||||||||||||||
logger.LogError( | ||||||||||||||||||||||||||||||||||||||||||
ex, | ||||||||||||||||||||||||||||||||||||||||||
"Task {TaskId} failed with error: {ErrorMessage}", | ||||||||||||||||||||||||||||||||||||||||||
taskId, | ||||||||||||||||||||||||||||||||||||||||||
ex.Message | ||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
throw; | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||||||||||||
/// Run benchmark with configurable task count | ||||||||||||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||||||||||||
private static async Task RunBenchmarkAsync( | ||||||||||||||||||||||||||||||||||||||||||
int numTasks, | ||||||||||||||||||||||||||||||||||||||||||
ILogger logger) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
// Leverage .NET 9's improved concurrent collections | ||||||||||||||||||||||||||||||||||||||||||
var results = new ConcurrentBag<TaskMetrics>(); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
// Parallel task execution with improved task management | ||||||||||||||||||||||||||||||||||||||||||
var tasks = Enumerable.Range(0, numTasks) | ||||||||||||||||||||||||||||||||||||||||||
.Select(taskId => Task.Run(async () => | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
var result = await PerformTaskAsync(taskId, logger); | ||||||||||||||||||||||||||||||||||||||||||
results.Add(result); | ||||||||||||||||||||||||||||||||||||||||||
return result; | ||||||||||||||||||||||||||||||||||||||||||
})) | ||||||||||||||||||||||||||||||||||||||||||
.ToList(); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
// Efficient task completion tracking | ||||||||||||||||||||||||||||||||||||||||||
await Task.WhenAll(tasks); | ||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+113
to
+126
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are capturing locals in the closure and creating unnecessary delegates.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
// Comprehensive benchmark summary | ||||||||||||||||||||||||||||||||||||||||||
logger.LogInformation( | ||||||||||||||||||||||||||||||||||||||||||
"Benchmark completed. Total Tasks: {TotalTasks}, Successful Tasks: {SuccessfulTasks}", | ||||||||||||||||||||||||||||||||||||||||||
numTasks, | ||||||||||||||||||||||||||||||||||||||||||
results.Count | ||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
/// <summary> | ||||||||||||||||||||||||||||||||||||||||||
/// Main entry point with Native AOT support | ||||||||||||||||||||||||||||||||||||||||||
/// </summary> | ||||||||||||||||||||||||||||||||||||||||||
public static async Task Main(string[] args) | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
// Improved logging configuration | ||||||||||||||||||||||||||||||||||||||||||
using var loggerFactory = LoggerFactory.Create(builder => | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
builder | ||||||||||||||||||||||||||||||||||||||||||
.AddConsole() | ||||||||||||||||||||||||||||||||||||||||||
.SetMinimumLevel(LogLevel.Information); | ||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||
var logger = loggerFactory.CreateLogger<AsyncTasksBenchmark>(); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
// Parse task count with improved parsing | ||||||||||||||||||||||||||||||||||||||||||
int numTasks = args.Length > 0 | ||||||||||||||||||||||||||||||||||||||||||
? int.Parse(args[0]) | ||||||||||||||||||||||||||||||||||||||||||
: 100_000; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
await Task.WhenAll(tasks); | ||||||||||||||||||||||||||||||||||||||||||
// Benchmark execution | ||||||||||||||||||||||||||||||||||||||||||
await RunBenchmarkAsync(numTasks, logger); | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# .NET Async Tasks Benchmark | ||
|
||
## Performance Characteristics | ||
|
||
### Why .NET? | ||
|
||
- High-performance async/await model | ||
- Cross-platform runtime | ||
- Advanced memory management | ||
- Support for multiple concurrency models | ||
|
||
### Benchmark Methodology | ||
|
||
- Spawn 100,000 concurrent tasks | ||
- Each task sleeps for 10 seconds | ||
- Track memory and execution metrics | ||
|
||
## Performance Recommendations | ||
|
||
1. Use .NET 8.0+ runtime | ||
2. Enable tiered compilation | ||
3. Use Release configuration | ||
4. Consider native AOT compilation | ||
|
||
### Execution | ||
|
||
```bash | ||
dotnet run -c Release [num_tasks] | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,20 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net9.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<InvariantGlobalization>true</InvariantGlobalization> | ||
|
||
<!-- .NET 9 specific optimizations --> | ||
<PublishTrimmed>true</PublishTrimmed> | ||
<PublishAot>true</PublishAot> | ||
<TrimmerDefaultAction>link</TrimmerDefaultAction> | ||
Comment on lines
-8
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need the globalization here, which aligns with the behavior of other languages. Otherwise, it would lead the runtime to load ICU globalization data into the memory. |
||
</PropertyGroup> | ||
|
||
</Project> | ||
<ItemGroup> | ||
<!-- .NET 9 preview packages --> | ||
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.0-preview.1.*" /> | ||
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0-preview.1.*" /> | ||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0-preview.1.*" /> | ||
Comment on lines
+16
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you using preview versions while the 9.0 GA versions are present? |
||
</ItemGroup> | ||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
defmodule AsyncBenchmark do | ||
defstruct [:task_id, :start_time, :end_time, :duration] | ||
|
||
def perform_task(task_id) do | ||
start_time = :os.system_time(:millisecond) | ||
|
||
# Simulate 10-second task | ||
:timer.sleep(10000) | ||
|
||
end_time = :os.system_time(:millisecond) | ||
duration = end_time - start_time | ||
|
||
%__MODULE__{ | ||
task_id: task_id, | ||
start_time: start_time, | ||
end_time: end_time, | ||
duration: duration | ||
} | ||
end | ||
|
||
def spawn_tasks(num_tasks) do | ||
parent = self() | ||
|
||
tasks = Enum.map(0..(num_tasks - 1), fn task_id -> | ||
spawn_link(fn -> | ||
result = perform_task(task_id) | ||
send(parent, {:task_result, result}) | ||
end) | ||
end) | ||
|
||
# Collect results | ||
results = Enum.map(0..(num_tasks - 1), fn _ -> | ||
receive do | ||
{:task_result, result} -> result | ||
end | ||
end) | ||
|
||
# Optional: Print results | ||
Enum.each(results, fn result -> | ||
IO.puts "Task #{result.task_id} completed in #{result.duration / 1000} seconds" | ||
end) | ||
end | ||
|
||
def main(args \\ []) do | ||
# Parse number of tasks, default to 100,000 | ||
num_tasks = case args do | ||
[num_str] -> String.to_integer(num_str) | ||
_ -> 100_000 | ||
end | ||
|
||
spawn_tasks(num_tasks) | ||
end | ||
end | ||
|
||
# Run the benchmark | ||
AsyncBenchmark.main(System.argv()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should rely on external tools to measure the memory.
GC.GetTotalMemory
only accounts for managed memory which doesn't include the runtime overhead.