Производительность — это не только про оптимизацию сложных алгоритмов. Часто проблемы кроются в мелочах: лишние аллокации, блокировки потоков или неэффективные запросы к базе данных. Эти ошибки могут оставаться незамеченными, пока приложение не начнёт «тормозить» под нагрузкой.
1️⃣ Лишние аллокации объектов
Проблема: частое создание временных объектов нагружает сборщик мусора, что приводит к паузам в работе приложения.
Решение:
• Используйте пулы объектов (ArrayPool, MemoryPool) для переиспользования памяти.
• Для небольших данных применяйте struct вместо class.
// Плохо: аллокация на каждый вызов
var buffer = new byte[1024];
// Лучше: переиспользуем память
var pool = MemoryPool<byte>.Shared;
using (var owner = pool.Rent(1024))
{
var buffer = owner.Memory;
// Работа с буфером
}
2️⃣ Блокировка асинхронного кода
Проблема: Использование .Result или .Wait() блокирует текущий поток, что может привести к дедлокам, особенно в UI-приложениях.
Решение:
• Цепочка async/await должна идти от начала до конца.
• В библиотечных методах используйте .ConfigureAwait(false).
Пример:
// Плохо: блокировка потока
public string GetData() => FetchDataAsync().Result;
// Лучше: полная асинхронность
public async Task<string> GetDataAsync() => await FetchDataAsync();
3️⃣ Неэффективные запросы к БД
Проблема:
• N+1 запросы в ORM (например, Entity Framework).
• Отсутствие индексов или выборка лишних данных.
Решение:
• Используйте .Include() для жадной загрузки связанных данных.
• Применяйте пагинацию (Skip/Take) и индексы.
// Плохо: N+1 запросов
var orders = context.Orders.ToList();
foreach (var order in orders)
{
var customer = context.Customers.Find(order.CustomerId);
}
// Лучше: один запрос с JOIN
var orders = context.Orders.Include(o => o.Customer).ToList();
➡️ Эти 3 антипаттерна — частые «узкие места». Проверьте их в своём коде, а остальные 7 примеров смотрите в статье
