Start Debugging

Тег: comparison

72 статей · Страница1из8

Итератор yield return или возврат List<T>: сколько на самом деле стоит метод с IEnumerable в C#
Метод с yield return стоит один 40-байтовый объект конечного автомата на вызов, сколько бы элементов он ни выдавал; List<T> сразу выделяет весь внутренний массив. Замеры на .NET 10.0.10: итератор выигрывает по памяти и при раннем выходе, List<T> выигрывает, когда вызывающий код перечисляет больше одного раза, нуждается в Count или вызывает ToList().
Сеттер FileSystemInfo.LastWriteTime или File.SetLastWriteTime в .NET
Оба пути заканчиваются одним и тем же вызовом ОС, поэтому записанная метка времени идентична. Различия кроются вокруг этого вызова: какой кеш сбрасывается, работают ли каталоги в Windows, как преобразуется DateTime не в UTC и можно ли указать открытый дескриптор. Используйте File.SetLastWriteTimeUtc, а для открытого файла передавайте дескриптор. Проверено на .NET 10.0.10.
Цикл по ref T против индексации Span<T> в C#: почему версия со span не медленнее, а часто быстрее в .NET 10
В .NET 10 обычный цикл for по span[i] с границей span.Length компилируется в цикл без проверки границ, со снижением стоимости операций (strength reduction) и обратным отсчётом. Написанный вручную цикл с Unsafe.Add(ref r, i) и индексом int сохраняет расширение знака и сравнение при счёте вверх и в замерах оказался на 2-5% медленнее. Бенчмарки и дизассемблер JIT для arm64 и x64 на .NET 10.0.10.
shared_preferences или JSON-файл через path_provider для хранения настроек во Flutter
shared_preferences (SharedPreferencesWithCache) подходит для нескольких плоских флагов, а JSON-файл в getApplicationSupportDirectory подходит для структурированного объекта настроек. Разбираем атомарную запись, состояние гонки при параллельных сохранениях, ловушку с папкой Documents в Windows и Linux, поддержку веба и измеренную стоимость записи на Flutter 3.44.8.
Expanded или Flexible во Flutter: разбор FlexFit.tight и FlexFit.loose
Используйте Expanded, когда дочерний виджет должен занять свою долю Row или Column, и Flexible, когда он может быть меньше своей доли. Замеры раскладки на Flutter 3.44 показывают, куда уходит оставшееся место, почему неплотные дочерние виджеты не отдают его соседям и когда при неограниченных ограничениях работает только Flexible.
Lazy<T> vs LazyInitializer.EnsureInitialized vs блокировка с двойной проверкой в C#
По умолчанию используйте Lazy<T>: он выполняет фабрику один раз, кеширует исключения, а чтение после инициализации слишком дёшево, чтобы его можно было измерить. LazyInitializer.EnsureInitialized подходит, когда вы лениво заполняете много полей или ячеек массива и не можете позволить себе лишний объект на каждое значение. Ручная блокировка с двойной проверкой на .NET 10 почти никогда не оправдана.
unawaited_futures и discarded_futures в Dart: какой линтер ловит какой вызов без await
unawaited_futures смотрит только внутрь async-тел, discarded_futures только внутрь синхронных, и оба пропускают стрелочные функции, tear-off и литералы коллекций. Разбор по случаям на Dart 3.12.2 и Flutter 3.44.8 и analysis_options.yaml, который я рекомендую.
FileSystemWatcher или опрос для обнаружения изменений файлов на сетевой папке в .NET
На SMB- или NFS-ресурсе источником истины служит опрос, а FileSystemWatcher в лучшем случае подсказка. FileSystemWatcher пропускает удалённые изменения на Linux и macOS, переполняет 64-килобайтный сетевой буфер и навсегда останавливается при обрыве соединения. Используйте периодическое сравнение снимков, а наблюдателю оставьте только роль триггера для досрочного сканирования. Проверено на .NET 10.0.10.
Thread.Sleep, Task.Delay и SpinWait для ожидания в C#
Используйте await Task.Delay для любого ожидания по времени в асинхронном коде, Thread.Sleep только на выделенном потоке, которым вы владеете, а SpinWait только для ожиданий короче микросекунды внутри lock-free кода. Чтобы дождаться условия, применяйте сигнал (ManualResetEventSlim, SemaphoreSlim, TaskCompletionSource) вместо любого из этих трёх. Измерено на .NET 10.0.10.
AddDbContextPool или AddDbContextFactory для параллельного выполнения запросов EF Core
AddDbContextPool выдаёт один scoped DbContext на область DI, поэтому не может выполнять два запроса одновременно. AddDbContextFactory и AddPooledDbContextFactory дают контекст на каждый вызов, а именно это нужно параллельным запросам. Замеры на EF Core 11 RC 1: пулированная фабрика создаёт контекст за 342 нс и 40 Б против 17 мкс и 44 КБ.
Вперёд