C# (C Sharp) programming
前往频道在 Telegram
По всем вопросам- @notxxx1 Реестр РКН: https://clck.ru/3Fk3kb #VRHSZ
显示更多📈 Telegram 频道 C# (C Sharp) programming 的分析概览
频道 C# (C Sharp) programming (@csharp_ci) 俄语 语言赛道中的 是活跃参与者。目前社区聚集了 18 267 名订阅者,在 技术与应用 类别中位列第 7 188,并在 俄罗斯 地区排名第 36 612 位。
📊 受众指标与增长动态
自 невідомо 创建以来,项目保持高速增长,吸引了 18 267 名订阅者。
根据 13 七月, 2026 的最新数据,频道保持稳定运转。过去 30 天订阅人数变化为 -47,过去 24 小时变化为 -2,整体触达仍然可观。
- 认证状态: 未认证
- 互动率 (ER): 平均受众互动率为 15.20%。内容发布后 24 小时内通常能获得 7.79% 的反应,占订阅者总量。
- 帖子覆盖: 每篇帖子平均可获得 2 776 次浏览,首日通常累积 1 423 次浏览。
- 互动与反馈: 受众积极参与,单帖平均反应数为 0。
- 主题关注点: 内容集中在 .net, api, логика, архитектура, string 等核心主题上。
📝 描述与内容策略
作者将该频道定位为表达主观观点的平台:
“По всем вопросам- @notxxx1
Реестр РКН: https://clck.ru/3Fk3kb
#VRHSZ”
凭借高频更新(最新数据采集于 14 七月, 2026),频道始终保持新鲜度与高覆盖。分析显示受众积极互动,使其成为 技术与应用 类别中的关键影响点。
18 267
订阅者
-224 小时
-377 天
-4730 天
数据加载中...
相似频道
标签云
进出提及
---
---
---
---
---
---
吸引订阅者
七月 '26
七月 '26
+31
在0个频道中
六月 '26
+147
在3个频道中
Get PRO
五月 '26
+131
在2个频道中
Get PRO
四月 '26
+76
在1个频道中
Get PRO
三月 '26
+96
在23个频道中
Get PRO
二月 '26
+112
在45个频道中
Get PRO
一月 '26
+398
在132个频道中
Get PRO
十二月 '25
+117
在5个频道中
Get PRO
十一月 '25
+318
在44个频道中
Get PRO
十月 '25
+84
在14个频道中
Get PRO
九月 '25
+162
在37个频道中
Get PRO
八月 '25
+223
在9个频道中
Get PRO
七月 '25
+418
在77个频道中
Get PRO
六月 '25
+293
在71个频道中
Get PRO
五月 '25
+238
在1个频道中
Get PRO
四月 '25
+191
在28个频道中
Get PRO
三月 '25
+185
在2个频道中
Get PRO
二月 '25
+210
在42个频道中
Get PRO
一月 '25
+200
在46个频道中
Get PRO
十二月 '24
+416
在56个频道中
Get PRO
十一月 '24
+1 096
在187个频道中
Get PRO
十月 '24
+1 800
在73个频道中
Get PRO
九月 '24
+635
在199个频道中
Get PRO
八月 '24
+662
在44个频道中
Get PRO
七月 '24
+665
在53个频道中
Get PRO
六月 '24
+1 168
在60个频道中
Get PRO
五月 '24
+565
在39个频道中
Get PRO
四月 '24
+569
在45个频道中
Get PRO
三月 '24
+709
在21个频道中
Get PRO
二月 '24
+1 055
在2个频道中
Get PRO
一月 '24
+1 376
在46个频道中
Get PRO
十二月 '23
+608
在44个频道中
Get PRO
十一月 '23
+1 091
在30个频道中
Get PRO
十月 '23
+332
在19个频道中
Get PRO
九月 '23
+352
在0个频道中
Get PRO
八月 '23
+1 949
在0个频道中
Get PRO
七月 '23
+507
在0个频道中
Get PRO
六月 '23
+1 238
在0个频道中
Get PRO
五月 '23
+1 891
在0个频道中
Get PRO
四月 '23
+3 025
在0个频道中
Get PRO
三月 '23
+1 858
在0个频道中
Get PRO
二月 '23
+85
在0个频道中
Get PRO
一月 '23
+113
在0个频道中
Get PRO
十二月 '22
+171
在0个频道中
Get PRO
十一月 '22
+226
在0个频道中
Get PRO
十月 '22
+197
在0个频道中
Get PRO
九月 '22
+170
在0个频道中
Get PRO
八月 '22
+756
在0个频道中
Get PRO
七月 '22
+82
在0个频道中
Get PRO
六月 '22
+152
在0个频道中
Get PRO
五月 '22
+344
在0个频道中
Get PRO
四月 '22
+256
在0个频道中
Get PRO
三月 '22
+53
在0个频道中
Get PRO
二月 '22
+45
在0个频道中
Get PRO
一月 '22
+97
在0个频道中
Get PRO
十二月 '21
+45
在0个频道中
Get PRO
十一月 '21
+1 110
在0个频道中
| 日期 | 订阅者增长 | 提及 | 频道 | |
| 14 七月 | +2 | |||
| 13 七月 | 0 | |||
| 12 七月 | 0 | |||
| 11 七月 | +3 | |||
| 10 七月 | +2 | |||
| 09 七月 | 0 | |||
| 08 七月 | +1 | |||
| 07 七月 | 0 | |||
| 06 七月 | +3 | |||
| 05 七月 | +3 | |||
| 04 七月 | +1 | |||
| 03 七月 | +6 | |||
| 02 七月 | +7 | |||
| 01 七月 | +3 |
频道帖子
TIME_WAIT в Linux годами объясняют неправильно
Я полез в исходники Linux TCP и снова наткнулся на старый сетевой миф.
В коде TIME_WAIT фактически зафиксирован на 60 секунд:
#define TCP_TIMEWAIT_LEN (60 * HZ)
Его нельзя настроить отдельно для сокета.
И да, tcp_fin_timeout, который часто советуют крутить в блогах, не управляет TIME_WAIT.
Он относится к состоянию FIN_WAIT2.
TIME_WAIT задан в исходниках ядра и не вынесен в отдельный sysctl.
Вот так появляются мифы: один параметр звучит похоже, его копируют из статьи в статью, а потом годами лечат не то состояние TCP.
| 2 | G# — новый язык для .NET с синтаксисом ближе к Go, Kotlin и Swift.
Идея не в том, чтобы заменить C#, а в том, чтобы дать более компактный язык поверх той же CLR.
Что обещают:
• компиляция в обычные managed .NET assemblies
• совместимость с BCL, NuGet, MSBuild и dotnet tooling
• interop с C#-кодом
• null-safety через T?, nil, ?., ??, if let и guard let
• data classes со structural equality, copy-with и deconstruction
• async/await поверх Task и Task[T]
• опциональные Go-подобные go, chan, select
• REPL / script runner через gsi
• C# → G# мигратор через cs2gs
Самая интересная часть — G# не пытается строить новый рантайм. Он просто использует существующую .NET-экосистему и меняет язык входа: меньше исторического багажа C#, больше предсказуемой синтаксической поверхности.
Но важно: проект пока pre-1.0. Версия 0.3 — это скорее milestone по реализации и interop, а не гарантия стабильности языка.
Для продакшена рано. Для тех, кто следит за экспериментами вокруг .NET-языков, очень любопытно.
Статья: https://www.linkedin.com/pulse/meet-g-modern-net-language-go-kotlin-swift-ergonomics-david-obando-lwofc/ | 2 379 |
| 3 | Ты не твой стек
Зачем учиться новому, когда по самое колено в практике? Не страшно, что всё больше джунов работают наравне с сеньёрами?
Уже нельзя уметь только фреймворк, надо понимать что стоит за этим и в твоём опыте огромное преимущество, не хватает лишь малого - знаний об том как утроен мир и формула принятия решений.
Метафизика? Нет - математика.
Языки и фреймворки устаревают за 5–10 лет, стеки обновляются радикально. А способ мышления, которым ты пользуешься, чтобы разложить сложную задачу на части, остаётся с тобой навсегда.
Именно об этом курс: "Философия, математика и компьютерные науки"
Не про конкретный стек, а про то, как в принципе думать о сложных системах с опорой на философию, математику и системную инженерию.
Формат:
9 месяцев, 10 модулей, теория и практика, несколько очных сессий в Петербурге.
Кураторы:
- Андрей Родин — доктор философских наук, философ науки и математики
- Илья Егорычев — доктор философских наук, математик и логик, Soulmaths
- Вячеслав Шириков — системный архитектор, техдиректор ГК «Лартех»
До 21 июля действует скидка за раннюю регистрацию.
Программа и условия | 2 128 |
| 4 | ⚡️ GPT-5.6 РЕЛИЗ
OpenAI выкатили сразу три новые модели.
• Sol - заявлено, что модель мощнее Mythos. Доступ для платных пользователей обещают в течение 24 часов.
На Terminal Bench 2.1 с настройкой Ultra модель выбивает рекордные 91,9%.
Первые тестеры отдельно отмечают сильную работу с интерфейсами: она уверенно собирает UI для приложений и сайтов, а не просто генерирует сырой код.
• Terra - уровень Fable 5. Будет доступна бесплатно.
• Luna - еще одна бесплатная модель для всех.
Помимо самой модели, показали 3 крупных продуктовых обновления:
1. ChatGPT Work
2. новое desktop-приложение ChatGPT
3. hosted sites, то есть размещение сайтов прямо через Chatgpt
https://openai.com/ru-RU/live/ | 1 |
| 5 | #ПятничныйКвиз | 2 209 |
| 6 | AI-инструменты стали стандартной частью стека C#/.NET-разработчиков: ассистенты в IDE, генерация кода и тестов, помощь с документацией и ревью.
По данным отраслевых отчётов, 80–90% инженеров уже используют AI-сервисы, а 97% компаний встроили AI в SDLC.
Однако разрыв сегодня проходит не по доступу к моделям. У одних команд AI встроен в мультиагентные пайплайны, SDD подход и метрики качества. У других остаётся локальным помощником без влияния на метрики, скорость релизов и риск-профиль.
Именно для интеграции AI в процессы команда Naition запускает 12‑недельную программу по AI-driven разработке. Программу собрали инженеры и техлиды из Яндекс Cloud, Сбера, Google и других продуктовых команд с опытом более 15 лет.
Что внутри:
• создание AI-окружения под ваш стек
• контекст-инжиниринг - от создания и подключения кастомных MCP до RAG под вашу кодовую базу
• решение продуктовых задач, spec-driven разработка и контроль качества с evals
• разработка агентов, сабагентов с выходом в практики оркестрации
• практики работы с легаси-проектами и крупными кодовыми базами при ограниченном бюджете
Форматы участия:
Командный - для C#/.NET-команд от 3–5 человек. Заходите в общий поток и получаете отдельный трек: разбор текущих процессов, выделение узких мест, план внедрения AI-практик и фиксация метрик до и после изменений.
Индивидуальный формат - для архитекторов, техлидов, middle/senior‑разработчиков и руководителей, которые хотят собрать язык и паттерны AI‑ориентированной разработки, чтобы затем использовать их как основу изменений внутри своих команд.
95% участников прошлого потока дошли до конца. Первые изменения в процессах команды вносили уже после второго модуля.
Новый поток AI‑DRIVEN стартует 21 июля.
Если вы отвечаете за архитектуру и метрики разработки в C#/.NET‑проектах, вы можете оставить заявку на сайте и до 13 июля получить индивидуальные условия участия для команды или для себя как индивидуального участника.
Подробности на сайте: naition.ai
Реклама: ИП Крутов Дмитрий Валерьевич ИНН: 772973192199
Erid: 2VtzqxRqZmC | 2 103 |
| 7 | Godot фактически запрещает vibe coding в контрибуциях.
Причина простая: PR стало легче генерировать, но не легче проверять. Для open-source движка каждый патч всё равно должен разобрать мейнтейнер, который понимает архитектуру, риски и последствия изменений.
Теперь автономные агенты, крупные AI-сгенерированные куски кода и сгенерированный текст в issues, proposals и PR-дискуссиях запрещены. Разрешены только мелкие помощники вроде автодополнения, regex и find/replace. Помощь AI в коде нужно раскрывать.
На практике правило будет сложно применять: почти невозможно наверняка доказать, где был vibe coding, а где обычная работа разработчика.
Godot защищает не стиль разработки, а время ревьюеров. Код можно сгенерировать за минуты, но ответственность за него всё равно остаётся на людях.
godotengine.org/article/contribution-policy-2026/ | 3 256 |
| 8 | #ПятничныйКвиз | 3 153 |
| 9 | ⚡️ Idempotency: важная вещь в REST API
В распределённых системах запрос может не дойти, ответ может потеряться, клиент может словить timeout и отправить тот же запрос ещё раз.
Если API не готов к такому сценарию, начинаются дубли: два платежа, два заказа, две записи в базе.
Idempotency решает эту проблему.
Идемпотентная операция может быть вызвана несколько раз, но состояние системы после первого успешного запроса уже не меняется.
Типичный пример: клиент создаёт уникальный ключ операции и отправляет его в заголовке, например:
Idempotency-Key: 8f7a2c9e-12a4-4f8b-91c2
Сервер проверяет этот ключ.
Если ключ новый, он выполняет операцию и сохраняет результат.
Если ключ уже был, сервер не запускает операцию повторно, а возвращает сохранённый ответ.
Так API нормально переживает повторы, сетевые сбои и retries без случайных дублей.
Особенно важно для платежей, создания заказов, бронирований и любых операций, где повторный запрос может стоить денег. | 3 273 |
| 10 | # C# record: что выведет код?
На собеседованиях record часто объясняют как «сравнение по значению». Но есть нюанс, который легко пропустить.
public record User(string Name, List<string> Roles);
var u1 = new User("Alice", new List<string> { "admin" });
var u2 = u1 with { };
u2.Roles.Add("owner");
Console.WriteLine(u1 == u2);
Console.WriteLine(string.Join(", ", u1.Roles));
Console.WriteLine(ReferenceEquals(u1.Roles, u2.Roles));
Что будет в консоли?
True
admin, owner
True
Почему так?
with для record делает не глубокую копию, а поверхностную. Сам объект User скопировался, но List<string> внутри остался тем же самым объектом в памяти.
Поэтому изменение u2.Roles меняет и u1.Roles.
И сравнение тоже остаётся True, потому что оба record указывают на один и тот же список.
Вот почему record не делает модель автоматически immutable. Он только упрощает синтаксис и даёт value-based equality. Если внутри лежат изменяемые reference-типы, их всё равно можно случайно протащить в состояние.
Более безопасный вариант:
public record User(string Name, IReadOnlyList<string> Roles);
А для строгой неизменяемости лучше смотреть в сторону immutable collections. | 2 642 |
| 11 | Методы, их перегрузка и расширения. Бесплатный урок специализации «C#-разработчик»
Методы — одна из базовых вещей в C#, без которой невозможно нормально писать, читать и поддерживать код. Но у начинающих разработчиков часто всё смешивается: где обычный метод, где перегрузка, как работает сигнатура, зачем нужны параметры по умолчанию и в каких случаях использовать params.
На открытом уроке 2 июля в 20:00 разберём, что такое метод в C#, как писать собственные методы и как использовать перегрузку без хаоса в коде. Поговорим о сигнатуре метода, параметрах по умолчанию, ключевом слове params и методах-расширениях. На примерах покажем, как эти механики помогают делать код понятнее, гибче и удобнее для повторного использования.
Урок не для тех, кто хочет просто «выучить синтаксис» без понимания, как методы влияют на структуру программы.
👉 Записаться: https://otus.pw/Dbvh/?erid=2W5zFG69SGh
Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963. | 2 268 |
| 12 | Globbing. - это удобный способ искать файлы по маскам, без ручного перебора папок и костылей со строками.
Например:
**/*.cs - все C# файлы во всех вложенных папках
wwwroot/**/*.js - все JS-файлы внутри wwwroot
!bin/** и !obj/** - исключить мусорные директории сборки
Где это полезно:
• генерация списков файлов
• поиск конфигов
• обработка шаблонов
• сборка ассетов
• утилиты для проектов
• backend/frontend tooling
Это не Regex. Globbing проще, читаемее и отлично подходит для файловой структуры.
Backend пример:
https://github.com/karenpayneoregon/vs2026-how-to/blob/f1c136c864b05ec9eec91e120997314d978b0966/CommonLibrary/GlobbingOperations.cs?plain=1#L6C15-L6C15
Frontend пример:
https://github.com/karenpayneoregon/vs2026-how-to/blob/f1c136c864b05ec9eec91e120997314d978b0966/ExperimentsApp/Classes/GlobbingCode.cs?plain=1#L20C37-L20C37 | 2 310 |
| 13 | Классическая задача на собеседовании: вывести бинарное дерево по уровням.
На входе дерево:
1
2 3
4 5 6
Нужно не просто пройти узлы, а напечатать каждый уровень с новой строки.
Первое, что вспоминается, это BFS. Для обхода в ширину идеально подходит Queue<T>: кладём корень, достаём узел, добавляем его детей, повторяем.
Так легко получить порядок:
1 2 3 4 5 6
Но настоящая часть задачи начинается дальше: как понять, где закончился уровень?
Есть два нормальных варианта:
• хранить вместе с узлом его уровень
• на каждой итерации брать queue.Count и обрабатывать ровно столько узлов текущего уровня
Второй способ часто чище: размер очереди в начале цикла и есть количество элементов на текущем уровне.
Такие задачи редко проверяют «знание деревьев ради деревьев».
Они проверяют другое: умеешь ли ты разложить проблему, выбрать структуру данных и аккуратно контролировать состояние.
Для C# это отличный мини-тест на мышление, работу с Queue<T> и понимание алгоритмов без магии фреймворков. | 2 759 |
| 14 | Задачка C#
Зачем указывать RunContinuationsAsynchronously у TaskCompletionSource?
A - Чтобы продолжения выполнялись синхронно при SetResult
B - Чтобы не исполнять продолжения синхронно в потоке SetResult, а планировать их асинхронно, избегая дедлоков и глубоких стеков
C- Чтобы запретить отмену задач
D- Чтобы обойти планировщик и ускорить завершение | 3 844 |
| 15 | 🚀 DDD на C#: от теории к микросервису за 6 недель
Если ты пишешь на C# и в какой-то момент начал чувствовать, что вроде всё работает, но как-то костыльно — это тревожный сигнал.
Новая фича затрагивает десятки файлов. Тесты становятся сложнее самого кода. Любое изменение заставляет переживать, что сломается что-то ещё.
Обычно проблема не в разработчиках. Проблема в том, что проект растёт без понятной архитектурной модели.
На курсе по Domain-Driven Design и Clean Architecture на C# ты научишься:
— Отделять бизнес-логику от инфраструктуры
— Организовывать код так, чтобы новые требования не приводили к переписыванию половины сервиса
— Писать тесты, которые проверяют поведение системы, а не набор моков
— Подключать HTTP, gRPC и Kafka без изменений в доменной логике
— Строить сервисы, которые проще поддерживать и развивать
За 6 недель ты соберёшь полноценный микросервис на C# с DDD, Kafka, gRPC и Clean Architecture на реальном кейсе диспетчеризации заказов.
👨🏫 Автор курса — Кирилл Ветчинкин, архитектор Авито, ex Staff Engineer Купер, ex Head of Backend BCS Broker.
🎁 Первый модуль доступен бесплатно.
В нём разберём, почему кодовые базы со временем становятся хрупкими, откуда появляются сложные тесты и постоянный страх изменений, и как DDD и Clean Architecture помогают решить эти проблемы на практике.
Посмотри демо-модуль и оцени, насколько этот подход подходит для твоих проектов:
https://microarch.ru/courses/ddd/languages/csharp?utm_source=posev&utm_medium=erid:2VtzqwrtmqB&utm_campaign=3
Реклама. ИП Ветчинкин К.Е. ИНН: 773376451099 Erid: 2VtzqvzVXjP | 2 735 |
| 16 | Совет по .NET Aspire: не воспринимайте его только как удобную локальную панель.
Самая полезная часть начинается, когда у приложения появляется инфраструктура: API, Postgres, Redis, фоновые сервисы, переменные окружения и connection strings.
Вместо того чтобы вручную собирать docker-compose.yml, опишите сервисы в AppHost. Aspire Docker publisher сможет сгенерировать Compose-артефакты из этой модели.
Но важно понимать границу: Aspire не деплоит приложение за вас.
Он не заменяет CI/CD, не управляет секретами и не переносит контейнеры на сервер. Вам всё равно нужно собрать image, задать реальные env-переменные, скопировать файлы и запустить Docker Compose.
Зато это хороший баланс: меньше ручной YAML-рутины, но без магии, которая скрывает реальную схему деплоя. | 3 105 |
| 17 | 🖥 На Stepik обновили курс «C# с нуля до профи»
Представьте: через четыре месяца вы открываете чужой .NET-проект и читаете его как книгу.
IServiceCollection не вызывает ступора. async Task<IActionResult> пишется на автомате. Вы точно знаете, почему EF Core сгенерировал именно такой SQL - и как переписать запрос, чтобы он летал.
Это не фантазия. Это результат после 16 модулей, в которых каждая концепция объясняется через код и закрепляется практикой.
ООП, SOLID, LINQ, async/await, DI, EF Core, ASP.NET Core, Docker, Kubernetes - всё, что казалось магией, станет рабочим инструментом.
А бонусом - портфолио проектов: от CLI-утилит и REST API до собственного SaaS с multi-tenancy, JWT и деплоем в Kubernetes под TLS.
Скидка - 58% доступна 48 часов: https://stepik.org/a/282984/ | 2 871 |
| 18 | Тест прошёл. А PostgreSQL вообще в курсе?
Интеграционные тесты часто выглядят надёжно ровно до того момента, пока приложение не встречается с настоящей базой.
На локалке всё зелёное. В CI всё зелёное. Моки довольны. In-memory база тоже не против. А потом в проде внезапно выясняется, что реальный PostgreSQL иначе обрабатывает запрос, constraint не даёт сохранить данные, транзакция ведёт себя не так, как ожидалось, а Redis показывает проблему, которую тесты вообще не могли поймать.
Именно поэтому Testcontainers в .NET так хорошо заходят для интеграционных тестов. Вместо имитации базы вы поднимаете настоящий PostgreSQL, Redis или другой сервис в Docker-контейнере, прогоняете приложение против реальной зависимости и удаляете контейнер после тестов.
Это даёт намного больше уверенности, чем тесты против подмены. При этом не нужен общий тестовый сервер, который кто-то сломал, не почистил или настроил иначе.
В хорошей схеме контейнеры запускаются через fixture, приложение получает connection string динамически, версии образов фиксируются, а настройка прячется за небольшими helper-классами. Сам тест при этом остаётся читаемым: он проверяет бизнес-сценарий, а не превращается в простыню из настройки базы и очистки состояния.
Есть важный нюанс. Общие fixtures ускоряют тесты, но требуют дисциплины со shared state. Когда изоляция важнее скорости, лучше использовать отдельные fixtures и не ловить фантомные падения из-за данных, оставшихся от соседнего теста.
Мне нравится этот подход именно за баланс. Вы тестируете не идеальную игрушечную модель приложения, а поведение, максимально близкое к реальному окружению. Но без боли ручной инфраструктуры.
Поэтому в следующий раз, когда интеграционный тест прошёл против in-memory базы, стоит задать неприятный вопрос: а настоящая база с ним согласится? | 2 672 |
| 19 | Кеширование в ASP.NET Core: от IMemoryCache до Redis
Приложение работает быстро — пока растёт нагрузка на базу, увеличивается время ответа API, а масштабирование инфраструктуры не начинает обходиться слишком дорого.
Кеширование помогает снизить количество запросов к хранилищам, ускорить работу сервисов и эффективнее использовать ресурсы. Но результат зависит от того, какие данные попадают в кеш, где он хранится и как устроена инвалидация.
На открытом вебинаре разберём:
— какие данные стоит кешировать, а какие — нет;
— как выбрать стратегию инвалидации;
— как работают HTTP Cache, UseResponseCaching и IMemoryCache в ASP.NET Core;
— когда нужен распределённый кеш через IDistributedCache;
— как использовать Redis и чем он отличается от Memcached.
Открытый урок пройдёт 25 июня в 20:00 МСК в преддверии старта курса «C# ASP.NET Core разработчик».
Подробности и регистрация: https://otus.pw/wSp1/?erid=2W5zFJU5ydB
Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963. | 1 429 |
| 20 | Аллокации, которых нет в коде: охота на скрытый боксинг в .NET 10
Самая дорогая аллокация в вашем сервисе та, которой нет в исходниках. Вы написали struct ради zero-allocation, прошли code review, а в проде Gen0-коллекции все равно идут косяком. Потому что между вашим кодом и машинным кодом стоит компилятор, и он молча упаковывает ваш value-тип в кучу там, где вы этого не просили — а на код-ревью этого не видно.
TL;DR. Боксинг (boxing) в .NET - это не только object o = 42. Он прячется в вызовах интерфейсных методов на struct, в дефолтном ValueType.Equals, в params object[]-аргументах, в foreach по интерфейсу и в замыканиях. При этом часть “классических” примеров боксинга из старых гайдов на современном рантайме уже не аллоцирует — JIT научился их вырезать, и слепо копировать советы десятилетней давности вредно. Ниже — карта мест, где боксинг живёт и сейчас, отдельный разбор того, что рантайм уже оптимизировал, реальный мини-кейс, воспроизводимый бенчмарк на BenchmarkDotNet с MemoryDiagnoser, способ ловить упаковку через DOTNET_JitDisasm и dotnet-gcdump, и паттерны лечения без потери читаемости.
О версиях и числах. Всё прверялось на .NET 10 (текущий LTS) и C# 13/14-уровне компилятора, Release, без отладчика, BenchmarkDotNet с MemoryDiagnoser. На .NET 8/9 поведение в основном такое же, но отдельные оптимизации JIT отличаются между мажорными версиями — поэтому главный принцип статьи: не верьте на слово (в том числе мне), гоняйте MemoryDiagnoser на своей версии рантайма. Числа в таблицах ниже - иллюстративные, порядок величины, а не точные замеры с вашего железа.
Пролог: “у нас же всё на struct, откуда Gen0?”
Сервис на горячем пути считает метрики: миллионы маленьких readonly struct-значений в секунду, никакого new, никаких классов в hot path. По задумке — ноль аллокаций. На дашборде — стабильный поток Gen0-коллекций раз в несколько секунд под нагрузкой.
Профайлер показывает аллокации, но стек ведёт в метод, где в коде нет ни одного new. Там цикл по интерфейсу, пара вызовов .Equals(), передача значения в params-метод лога. Глазами — чисто. В машинном коде — box-инструкции на каждой итерации.
Это и есть скрытый боксинг: компилятор C# и JIT упаковывают ваш struct в объект на куче, потому что в конкретной точке кода value-тип нужно представить как ссылочный. Симптом — Gen0-коллекции “из ниоткуда”, и его не видно ни в code review, ни в дампе, пока не посмотришь на IL или дизасм.
Если тема близка - я регулярно разбираю такие штуки по C# и .NET (внутренности рантайма, перформанс, неочевидные грабли с замерами и дизасмом) в своём Telegram-канале: t.me/csharp_ci. Заходите, если интересно копаться глубже.
Что такое боксинг и почему он стоит дорого
Боксинг — это упаковка value-типа (struct, enum, примитив) в объект на управляемой куче. Рантайму нужно выделить заголовок объекта, скопировать туда значение и вернуть ссылку. Анбоксинг - обратная операция с проверкой типа.
Цена не в самой инструкции, а в последствиях: каждая упаковка - это аллокация в Gen0. Много мелких аллокаций на горячем пути означают частые Gen0-коллекции, паузы (пусть и короткие), вытеснение полезных данных из кэша и общий рост CPU на ровном месте. На сервисе с SLA по p99 это бьёт по хвосту латентности так же, как и любая другая лишняя аллокация.
В IL боксинг виден явно - инструкция box. Именно её мы и будем искать.
Читать дальше: https://habr.com/ru/articles/1049236/ | 2 905 |
