Блокировка UI-потока гораздо заметнее блокировки фонового потока, поэтому Task.Run(() => ...) может быть меньшим злом.
Если запускаемая функция блокирует поток Thread Pool и это ухудшает производительность — её можно запустить не на Thread Pool, а в отдельном потоке, создав его вручную, или следующим образом (в нынешней реализации .NET этот способ тоже создаёт новый поток):
В этом случае, блокирующий код внутри метода будет выполняться в отдельном потоке и заблокирует только его.
Однако постоянное создание новых потоков может ещё больше навредить производительности, а при выносе вычислений в отдельные потоки пропускная способность Thread Pool также может снизиться, но уже из-за загруженности самих процессорных ядер. Поэтому не всегда целесообразно использование новых потоков или флага LongRunning.
Такой способ будет работать, но дополнительный Task будет создаваться даже если в вызывающем коде нет контекста. Можно доработать и перекладывать в Thread Pool только если контекст есть, получится эквивалент способа 3 (с await EscapeContext())
Наиболее автоматизированное решение сейчас — генерировать .ConfigureAwait(false) через Fody. Но Fody — сторонняя приблуда, ещё и усложняющая сборку проекта. Конечно хочется нативного решения, на уровне dotnet sdk или рантайма, и идей, как это сделать описано уже много.
Если добавить в язык условный await(false) или await!! грязи меньше не станет, поэтому остановимся на первом proposal. Его можно реализовать, например, в виде configureawait context, по аналогии с nullable context
Только увы, proposal висит с 2015 года, и никакого результата. Cейчас .ConfigureAwait(false) реализован в виде структуры-обёртки над Task, т.е. на уровне стандартной библиотеки, реализация же proposal потребует знания о ConfigureAwait на стороне компилятора (Roslyn) или рантайма. Возможно, сложность заключается в этом. Или просто всем без разницы и время на это не выделили.
Можно ли var text = await Task.Run(() => GetTextAsync()); заменить на var text = await GetTextAsync().ConfigureAwait(false); Тот же вопрос, почему используется Task.Run, а не ConfigureAwait(false)
.ConfigureAwait(false) имеет смысл только в методах, которым не нужно возвращаться на UI поток. Если использовать его внутри метода, которому важен контекст, то произойдёт исключение при попытке обновить UI (Text.Text = text;), если выполнение перейдёт на Thread Pool.
Метод Task.Run в этих примерах разделяет код, которому контекст важен, и код, который может работать на Thread Pool без возврата в исходный контекст. Весь код, запущенный через Task.Run ничего не узнает про контекст синхронизации, в то же время Task, возвращённый Task.Run может ожидаться в нужном контексте — хоть синхронно, хоть асинхронно.
Проблема в том, что нужно вспомнить в нужный момент об этой особенности функции .Split() и дописать либо параметр, либо .Where(...).
Также при использовании Console.ReadLine().Split() для формата ввода "в столбик" придётся полностью переписать код. А с поэлементным можно сделать универсальный метод, которому не важен ни тип разделителей, ни их количество:
int[] ReadIntArray()
{
var array = new int[ReadInt()];
for (int i = 0; i < array.Length; ++i)
array[i] = ReadInt();
return array;
}
Вот так постепенно с уязвимостями интела, требованиями Windows 11 к TPM и замедлением райзенов в ней же и затягиваются гайки добровольно-принудительного обновления железа. Конечно не отрицаю, что уязвимость может быть реальной, но могли и настройку сделать вместо игр с подбором версии драйвера.
P.S. Чего стоит одно название утилиты, проверяющей требования для Windows 11 — "PC Health Check". Как будто PC не health, если не работает на Win 11
Далеко не только альтернативный клиент может стать причиной утечки. Банальный троян-скриншотер вполне может подглядеть сообщения из официального клиента, ну или локальный кэш можно стащить, много вариантов
Это решение, конечно, учитывая, что так можно добавить и чёрный список слов для фильтрации рекламы от самих каналов, но:
Чужой сборке нельзя доверять в наше непростое время
При обновлениях клиента понадобится пересобирать его самостоятельно (а в случае с чужим форком — изучать все новые патчи)
Необходимо проделать на всех платформах, особый геморрой на iOS
У меня ещё свежи воспоминания о войне ICQ с альтернативными клиентами. Если такое произойдёт с телеграмом — это конец. Но это очень маловероятно, вряд ли телеграм опустится до баннеров
Имхо, самый адекватный вариант, если нет желания брать подписку или таковой не будет — вынести каналы в отдельный аккаунт, чтобы не отвлекали. В конце концов, контент массовых телеграм каналов и так засорён их собственной рекламой.
Но пересобрать ещё и с фильтрацией сообщений — годная тема
Это на какой монете получается выжать 2-3к? Это нереалистично. Полгода окупаемость будет если крипта и дальше вверх пойдёт, по нынешним ценам больше года. Ну а так действительно здравая мысль для тех, кто хочет отбить затраты, со своими рисками, конечно
Ray Tracing сам по себе бьёт по производительности, большинство игр и без него выглядят достойно, учитывая, что игры которые выйдут скоро разрабатываются давно — вряд ли лучи будут минимальным требованием. Если есть возможность взять 1070ti/1080/1080ti или из новых 1660super и разница в цене с 30 серией ощутимая — почему бы и нет, если играть только в FullHD. Не самые новые игры, Ведьмак 3 например, пойдут и в 2к. Но 3060(ti) держится наравне с топами 10 поколения.
Ещё есть вариант купить ноут с ноутбучной 3060, но там свои проблемы — перегревы, урезанная мощность видеокарт, невозможность апгрейда
Ещё вариант на computeruniverse посмотреть, с доставкой и пошлиной может выйти дешевле, чем в местных магазинах
Чёрный список слов, сообщения с которыми не отображаются, как в твиттере. Но такое не добавят — это убьёт рекламу в каналах. Похоже всё же придётся это костылить для себя самостоятельно, но с iOS клиентом это будет полный гемор (но от чтения спама я сойду с ума быстрее)
До этой истории я не знал, что вообще есть какой-то Агапитов, а теперь про этого гения менеджмента слышно из каждого утюга. Те, кто продолжает писать про эту историю несмотря на отсутствие новостей и новых фактов — делают ему бесплатную (или наоборот, проплаченную) рекламу
Я конкретно о категории Process, которая собирает данные медленно. Соответствие между инстансами в ней и PID как-то применимо в других категориях? Выглядит так, что в других категориях — свои имена инстансов, а в самой категории Process нет метрик, без которых нельзя обойтись или извлечь другим способом
Атомарность есть на уровнях NtQuerySystemInformation и Pdh, если в один query добавить сразу несколько каунтеров, включая ID Process.
.net.process — это тот, что System.Diagnostics.Process? Дотнетные обёртки что для процесса, что для перфкаунтеров сами по себе тяжеловесные. В версии 4.7.2 и Core частично исправили ситуацию, но все равно.
Hard-way ETW, конечно, не предлагаю, но там есть и эвенты с уже готовыми метриками, перформанс их конечно надо исследовать. Hard-way с ручным подсчётом если и использовать, то, например, для метрик по времени работы GC, которые не вытащить другими способами.
А какие уникальные метрики нужны из категории Process?
можно взять инстанс и сопоставить его с запущенным процессом, а лучше всего это делать в момент его запуска
Один раз взять не получится, выше там уже сказано, что инстанс ид могут сдвинуться. Хуже того, в .NET-категориях, например, наоборот, при запуске нового процесса (а точнее при первом GC в новом процессе, т.к. значения в .NET-категориях обновляются после GC) номера уже запущенных инстансов увеличиваются.
Если хочется прочитать что-то из категории Process, то это, имхо, лучше всего сделать добавив в PdhQuery сразу нужный каунтер и ID Process. Или пойти в обход каунтеров и вызывать напрямую NtQuerySystemInformation(5) (5 — это SystemProcessInformation). Так или иначе вся категория Process сведётся к этому вызову. На практике же хватает периодического обновления мапа между инстансами и process id.
Но т.к. NtQuerySystemInformation(5)работает за O(processes+threads), то при утечке потоков или их некорректном завершении из-за кривых драйверов, например, имеет огромные шансы добить систему окончательно, имхо лучше вообще категории Process и Thread избегать по возможности. Например использовать более легкие функции GetProcessMemoryInfo, GetProcessTime/GetSystemTime для мониторинга метрик по памяти/cpu одного процесса. IO метрики по диску надо придумать, откуда ещё можно вытащить, если они нужны. В IPHlpApi можно взять метрики по сетевой активности.
Если начинать использовать ETW — то логично это делать не только для отслеживания запуска/завершения процессов, а извлекать куда более интересные метрики из эвентов. Сходу не скажу, но скорее всего через ETW можно вытащить большинство метрик, что есть в перф каунтерах (как минимум стоит в PerfView протыкать IIS и MemInfo), но тут опять надо смотреть, из насколько медленных источников эти метрики попадают в ETW, не из того же ли NtQuerySystemInformation в случае метрик по памяти.
А для мониторинга бизнес-логики по типу запросов, имхо, нет ничего надёжнее ручной отправки из приложения
Как только зараженный неведомым зловредом ноутбук будет подключен к внутренней сети компании, то последняя может быть скомпрометирована за считанные минуты.
Как будто зловред и так не может проникнуть в сеть через корпоративный VPN или просто получить доступ к рабочим файлам, не будучи подключенным к офисной сети
Блокировка UI-потока гораздо заметнее блокировки фонового потока, поэтому
Task.Run(() => ...)
может быть меньшим злом.Если запускаемая функция блокирует поток Thread Pool и это ухудшает производительность — её можно запустить не на Thread Pool, а в отдельном потоке, создав его вручную, или следующим образом (в нынешней реализации .NET этот способ тоже создаёт новый поток):
В этом случае, блокирующий код внутри метода будет выполняться в отдельном потоке и заблокирует только его.
Однако постоянное создание новых потоков может ещё больше навредить производительности, а при выносе вычислений в отдельные потоки пропускная способность Thread Pool также может снизиться, но уже из-за загруженности самих процессорных ядер. Поэтому не всегда целесообразно использование новых потоков или флага
LongRunning
.Такой способ будет работать, но дополнительный
Task
будет создаваться даже если в вызывающем коде нет контекста.Можно доработать и перекладывать в Thread Pool только если контекст есть, получится эквивалент способа 3 (с
await EscapeContext()
)Корень проблемы
.ConfigureAwait(...)
на мой взгляд в том, что она сталкивает разработчиков библиотек и UI-кода:разработчики библиотек не хотят засорять код
.ConfigureAwait(false)
разработчики UI —
.ConfigureAwait(true)
,await Task.Run(() => ...)
Наиболее автоматизированное решение сейчас — генерировать
.ConfigureAwait(false)
через Fody. Но Fody — сторонняя приблуда, ещё и усложняющая сборку проекта. Конечно хочется нативного решения, на уровне dotnet sdk или рантайма, и идей, как это сделать описано уже много.Атрибут для сборки/параметр
*.csproj
https://github.com/dotnet/csharplang/issues/2542
Переопредение оператора
await
на уровне проектаhttps://github.com/dotnet/csharplang/issues/2649
Короткий синтаксис для `.ConfigureAwait(false)
https://github.com/dotnet/csharplang/discussions/645
Новый вид
Task/Task<T>
, свободный от контекста (даже есть реализация, но кажется, что overkill)https://github.com/ufcpp/ContextFreeTask
Если добавить в язык условный
await(false)
илиawait!!
грязи меньше не станет, поэтому остановимся на первом proposal. Его можно реализовать, например, в видеconfigureawait context
, по аналогии сnullable context
С ним в
*.csproj
можно было бы писать:А в файле с кодом
*.cs
:Только увы, proposal висит с 2015 года, и никакого результата. Cейчас
.ConfigureAwait(false)
реализован в виде структуры-обёртки надTask
, т.е. на уровне стандартной библиотеки, реализация же proposal потребует знания оConfigureAwait
на стороне компилятора (Roslyn) или рантайма. Возможно, сложность заключается в этом. Или просто всем без разницы и время на это не выделили..ConfigureAwait(false)
имеет смысл только в методах, которым не нужно возвращаться на UI поток. Если использовать его внутри метода, которому важен контекст, то произойдёт исключение при попытке обновить UI (Text.Text = text;
), если выполнение перейдёт на Thread Pool.Метод
Task.Run
в этих примерах разделяет код, которому контекст важен, и код, который может работать на Thread Pool без возврата в исходный контекст. Весь код, запущенный черезTask.Run
ничего не узнает про контекст синхронизации, в то же времяTask
, возвращённыйTask.Run
может ожидаться в нужном контексте — хоть синхронно, хоть асинхронно.Можно и так, и так.
Проблема в том, что нужно вспомнить в нужный момент об этой особенности функции
.Split()
и дописать либо параметр, либо.Where(...)
.Также при использовании
Console.ReadLine().Split()
для формата ввода "в столбик" придётся полностью переписать код. А с поэлементным можно сделать универсальный метод, которому не важен ни тип разделителей, ни их количество:В будущих версиях языка (начиная с C# 11) это будет не нужно
https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#improved-method-group-conversion-to-delegate
Я почему-то вначале подумал, что билеты на конференцию продаются прямо в приложении СберМегаМаркет, и на них можно потратить бонусы
Вот так постепенно с уязвимостями интела, требованиями Windows 11 к TPM и замедлением райзенов в ней же и затягиваются гайки добровольно-принудительного обновления железа. Конечно не отрицаю, что уязвимость может быть реальной, но могли и настройку сделать вместо игр с подбором версии драйвера.
P.S. Чего стоит одно название утилиты, проверяющей требования для Windows 11 — "PC Health Check". Как будто PC не health, если не работает на Win 11
Далеко не только альтернативный клиент может стать причиной утечки. Банальный троян-скриншотер вполне может подглядеть сообщения из официального клиента, ну или локальный кэш можно стащить, много вариантов
Это решение, конечно, учитывая, что так можно добавить и чёрный список слов для фильтрации рекламы от самих каналов, но:
Чужой сборке нельзя доверять в наше непростое время
При обновлениях клиента понадобится пересобирать его самостоятельно (а в случае с чужим форком — изучать все новые патчи)
Необходимо проделать на всех платформах, особый геморрой на iOS
У меня ещё свежи воспоминания о войне ICQ с альтернативными клиентами. Если такое произойдёт с телеграмом — это конец. Но это очень маловероятно, вряд ли телеграм опустится до баннеров
Имхо, самый адекватный вариант, если нет желания брать подписку или таковой не будет — вынести каналы в отдельный аккаунт, чтобы не отвлекали. В конце концов, контент массовых телеграм каналов и так засорён их собственной рекламой.
Но пересобрать ещё и с фильтрацией сообщений — годная тема
Это на какой монете получается выжать 2-3к? Это нереалистично. Полгода окупаемость будет если крипта и дальше вверх пойдёт, по нынешним ценам больше года. Ну а так действительно здравая мысль для тех, кто хочет отбить затраты, со своими рисками, конечно
Ray Tracing сам по себе бьёт по производительности, большинство игр и без него выглядят достойно, учитывая, что игры которые выйдут скоро разрабатываются давно — вряд ли лучи будут минимальным требованием. Если есть возможность взять 1070ti/1080/1080ti или из новых 1660super и разница в цене с 30 серией ощутимая — почему бы и нет, если играть только в FullHD. Не самые новые игры, Ведьмак 3 например, пойдут и в 2к. Но 3060(ti) держится наравне с топами 10 поколения.
Ещё есть вариант купить ноут с ноутбучной 3060, но там свои проблемы — перегревы, урезанная мощность видеокарт, невозможность апгрейда
Ещё вариант на computeruniverse посмотреть, с доставкой и пошлиной может выйти дешевле, чем в местных магазинах
Чёрный список слов, сообщения с которыми не отображаются, как в твиттере. Но такое не добавят — это убьёт рекламу в каналах. Похоже всё же придётся это костылить для себя самостоятельно, но с iOS клиентом это будет полный гемор (но от чтения спама я сойду с ума быстрее)
Похоже попытка прорекламировать личный блог провалилась. Ведь сейчас полная версия статьи доступна лишь в веб архиве
http://web.archive.org/web/20130315164343/http://www.claris-verbis.ru/TN_VA_IPS
Хорошими делами прославиться нельзя.
До этой истории я не знал, что вообще есть какой-то Агапитов, а теперь про этого гения менеджмента слышно из каждого утюга. Те, кто продолжает писать про эту историю несмотря на отсутствие новостей и новых фактов — делают ему бесплатную (или наоборот, проплаченную) рекламу
Я конкретно о категории
Process
, которая собирает данные медленно. Соответствие между инстансами в ней и PID как-то применимо в других категориях? Выглядит так, что в других категориях — свои имена инстансов, а в самой категорииProcess
нет метрик, без которых нельзя обойтись или извлечь другим способомАтомарность есть на уровнях
NtQuerySystemInformation
иPdh
, если в один query добавить сразу несколько каунтеров, включаяID Process
..net.process — это тот, что
System.Diagnostics.Process
? Дотнетные обёртки что для процесса, что для перфкаунтеров сами по себе тяжеловесные. В версии 4.7.2 и Core частично исправили ситуацию, но все равно.Hard-way ETW, конечно, не предлагаю, но там есть и эвенты с уже готовыми метриками, перформанс их конечно надо исследовать. Hard-way с ручным подсчётом если и использовать, то, например, для метрик по времени работы GC, которые не вытащить другими способами.
А какие уникальные метрики нужны из категории
Process
?Один раз взять не получится, выше там уже сказано, что инстанс ид могут сдвинуться. Хуже того, в .NET-категориях, например, наоборот, при запуске нового процесса (а точнее при первом GC в новом процессе, т.к. значения в .NET-категориях обновляются после GC) номера уже запущенных инстансов увеличиваются.
Если хочется прочитать что-то из категории
Process
, то это, имхо, лучше всего сделать добавив вPdhQuery
сразу нужный каунтер иID Process
. Или пойти в обход каунтеров и вызывать напрямуюNtQuerySystemInformation(5)
(5 — это SystemProcessInformation). Так или иначе вся категорияProcess
сведётся к этому вызову. На практике же хватает периодического обновления мапа между инстансами и process id.Но т.к.
NtQuerySystemInformation(5)
работает заO(processes+threads)
, то при утечке потоков или их некорректном завершении из-за кривых драйверов, например, имеет огромные шансы добить систему окончательно, имхо лучше вообще категорииProcess
иThread
избегать по возможности. Например использовать более легкие функцииGetProcessMemoryInfo
,GetProcessTime/GetSystemTime
для мониторинга метрик по памяти/cpu одного процесса. IO метрики по диску надо придумать, откуда ещё можно вытащить, если они нужны. ВIPHlpApi
можно взять метрики по сетевой активности.Если начинать использовать ETW — то логично это делать не только для отслеживания запуска/завершения процессов, а извлекать куда более интересные метрики из эвентов. Сходу не скажу, но скорее всего через ETW можно вытащить большинство метрик, что есть в перф каунтерах (как минимум стоит в PerfView протыкать IIS и MemInfo), но тут опять надо смотреть, из насколько медленных источников эти метрики попадают в ETW, не из того же ли
NtQuerySystemInformation
в случае метрик по памяти.А для мониторинга бизнес-логики по типу запросов, имхо, нет ничего надёжнее ручной отправки из приложения
Как будто зловред и так не может проникнуть в сеть через корпоративный VPN или просто получить доступ к рабочим файлам, не будучи подключенным к офисной сети