Если вы когда-нибудь задумывались, можно ли запустить бенчмарк, используя всего один C#-файл, то ответ: да, можно. Начиная с .NET 10, существует возможность создавать C#-приложения в одном *.cs‑файле. Проблема в том, что BenchmarkDotNet (BDN) не поддерживает такие бенчмарки с настройками по умолчанию. В этой статье я покажу, как обойти это ограничение, используя режим in-process.
Что такое однофайловые C#-приложения?
Однофайловые C#-приложения — это функционал, который появился в .NET 10 и позволяет поместить весь код в один *.cs-файл и запускать его напрямую:
// HelloWorld.cs Console.WriteLine("Hello, world!");
Запуск:
dotnet HelloWorld.cs # или dotnet run HelloWorld.cs
Почему BenchmarkDotNet не работает «из коробки»?
По умолчанию BDN использует изоляцию на уровне процесса (process-level isolation): он генерирует, собирает и запускает отдельное консольное приложение для каждого бенчмарка. Такая изоляция обеспечивает более точные и стабильные измерения. В однофайловых приложениях .NET генерирует проект и собирает артефакты во временную папку. У BDN пока нет функционала для работы с такими проектами.
Обходим ограничение, используя in-process режим
Чтобы запустить бенчмарк в том же процессе, нужно использовать атрибут InProcess. Учтите, что такие измерения менее изолированы и на результаты может влиять хост-процесс.
Минимальный рабочий пример:
#:package BenchmarkDotNet@0.15.8 #:property Optimize=true #:property Configuration=Release #:property PublishAot=false using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; BenchmarkRunner.Run<Benchmarks>(); [InProcess] public class Benchmarks { [Benchmark] public Task Example() => Task.Delay(100); }
Возможно вы заметили, что указаны флаги Optimize=true, Configuration=Release и PublishAot=false.
Флаги Optimize и Configuration нужны потому, что иначе .NET запустит бенчмарк в режиме Debug и без оптимизаций. А, как известно, бенчмарки в режиме Debug менее точные.
Флаг PublishAot отключает AOT, который для файловых приложений включён по умолчанию. AOT может быть полезен для уменьшения времени запуска вашего однофайлового приложения, и BDN поддерживает NativeAOT, но для этого требуется дополнительная настройка BDN.
Запуск бенчмарка
Чтобы запустить бенчмарк, выполните:
dotnet run Benchmark.cs
Если у вас Linux или macOS, то можно использовать shebang. Сначала найдите путь до dotnet:
which dotnet
Затем добавьте shebang в начало Benchmark.cs. В моём случае путь был /usr/bin/dotnet:
#!/usr/bin/dotnet run #:package BenchmarkDotNet@0.15.8 // ... остальной код
Сделайте файл исполняемым:
chmod +x Benchmark.cs
И запустите:
./Benchmark.cs
Вне зависимости от способа запуска вы увидите примерно такие результаты:
| Method | Mean | Error | StdDev | | ------- | -------: | ------: | ------: | | Example | 100.4 ms | 0.31 ms | 0.26 ms |
Вывод
Однофайловые C#-приложения можно использовать для бенчмаркинга, но для этого нужно запускать их в режиме in-process. Используя такой подход, помните, что такие бенчмарки менее изолированы и на результаты может влиять хост-процесс.
