Комментарии 26
Статья 2011 года нынче не так актуальна.
Из перечисленных технологий ( ASP.NET, Windows Forms, Windows Presentation Foundation (WPF), Silverlight ) всё уже в состоянии "никому не нужно".
В асп.нет кор от необходимости следить за контекстом синхронизации ушли, насколько я знаю, т.к. по умолчанию начали использовать тред-пул и синхронизировать нечего и незачем. Т.е. можно не думать о синхронизации, задедлочиться случайно довольно сложно.
Винформы актуальны только для миграций легаси на свежие фрейморки.
WPF примерно так же. Если кто-то пользуется, то понимать контекст синхронизации важно, но это важно уже сколько, лет 10?
И сильверлайт тоже умер на текущий момент.
Т.е. в реальности актуально сейчас только для десктопов WinForms и WPF. В 2024 наступающем не то чтобы самые актуальные технологии.
Я думаю Stephen Toub, который написал в начале этого-23-го года Пост: How Async/Await Really Works in C# с Вами бы не согласится, так как он пишет что:
However, it did add one notable advance that the APM pattern didn’t factor in at all, and that has endured into the models we embrace today:
SynchronizationContext
.
что, в контексте нашей дискуссии, можно перевести как:
<теперь у нас есть> одно заметное усовершенствование, которое шаблон APM вообще не учитывал, и которое сохранило свою ценность в моделях, которые мы используем сегодня: SynchronizationContext.
Это "сегодня" было датировано March 16th, 2023 .
Но возможно Вы знаете про какую-то более современную замену для SynchronizationContext? Поделитесь секретом? Просто я сомневаюсь, что такую фундаментальную концепцию как SynchronizationContext можно чем-то заменить, поэтому Ваш секрет был бы настоящим открытием для меня.
Потом, мне кажется, что .NET и даже C# в каком-то смысле, тоже технологии.
Формально SynchronizationContext всё ещё есть и работает, бесспорно. Но по факту, его учитывать стоит только в десктопных приложениях, которые на C# пишут достаточно редко. Спрос на такую разрботку не очень высокий.
ПС: и возможно в каких-то ещё UI приложениях, которые синхронизируют отрисовку силами одного треда, например https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
Если не секрет, а что пользуется спросом в сфере десктоп разработки сейчас?
Мне казалось, C# там должен быть среди первых
А нет в десктопе жизни. Если кто-то и пишет, то пишут обычно сразу кроссплатформ, что-то из веб-фреймворков, для десктопа заворачивают в электрон.
В C# из коробки кроссплатформа нет, существуют сторонние фреймворки, из которых я знаю разве что AvaloniaUI, но у меня сомнения, насколько он необходим. Веб писать и поддерживать возможно нынче легче.
В дотнете давно уже полная кроссплатформенность из коробки. Ничего никуда заворачивать не надо.
В контексте обсуждения подразумевалось, что нет кроссплатформенного UI в дотнете. К слову, всё ещё нет. Если есть - подскажите название хотя бы.
А MAUI не годится на роль кроссплатформенного?
Линуксов нет. С мобилками не совсем в курсе как дела, что-то было.
Не только. Я бэк интегрировал с Epic Online Services. Они требуют чтобы работа с апи была в единственном потоке. Плюс обёртка над их коллбеками для async/await. Пришлось писать свой SynchronizationContext (реализация sc для одного потока из vs не подошла)
Параллельные вычисления — Все дело в контексте-синхронизации (SynchronizationContext)
Больше интересует не программная реализация синхронизации (параллелизма), а формальная реализация параллелизма и конкуренции: синхронизация на схеме и математическим языком.
Есть классический пример описания параллелизма и конкуренции в алгебре процессов: одна кофе машина и два ученых. Два ученых бросают монеты не по очереди, а на конкурентной основе (случайно). Берет кофе тот, кто первым успеет и не обязательно, что он за этот кофе заплатил. После публикации статьи кофе машина готова принимать монеты.
Пример: An Introduction to Milner’s CCS
Есть ли более подробное описание этого примера (как в CCS \ LTS, так и на других языках)? Вообще, как в виде схем формализуются подобные алгоритмы? Схемы по ссылке не передают замысел сценария (синхронизация) в достаточном объеме.
Статья не про это, насколько я понимаю.
SynchronizationContext в дотнете - про контекст, в котором надо продолжить работу после выполнения асинхронной (в том числе возможно выполнения асинхронной на другом треде).
Т.е. речь про условную кофе машину, которая как раз запомнила (за счёт контекста), кто кинул монету, сварила асинхронно кофе, и вернула кофе именно тому, кто просил (вернула по контексту).
А вы хотите именно параллелизм и конкурентность - для этого в дотнете другие инструменты. Читать pdf мне лень, поэтому детальнее не скажу, как бы это выглядело. И да, задачу можно решать любым способом, не только случайным - т.е. можно формализовать, кто обязан получить кофе после оплаты, а можно оставить "на волю случая", и тогда обычно в дотнете это будет "кто последний, тот и прав", если отдельно не проработать случаи параллельного обращения к ресурсам.
SynchronizationContext в дотнете - про контекст, в котором надо продолжить работу после выполнения асинхронной
Насколько я понял, SynchronizationContext - про контекст который определяет как и/или где (в каком потоке) выполнять асинхронную операцию.
Вам ещё в прошлой статье сказали - нет у асинхронной операции потока.
Есть поток до асинхронщины, есть после. Сама асинхронность - это тот факт, что пока работа выполняется вне CPU (диск или сеть), поток может быть занят любой другой полезной работой.
И SynchronizationContext - это механизм, который для WPF позволяет выполнить работу после асинхронщины снова на UI-потоке (если вам это нужно).
Вам ещё в прошлой статье сказали - нет у асинхронной операции потока.
А если я запускаю какой-то свой, собственноручно написанный, сложный-тяжелый алгоритм расчета, которому больше негде выполняться как на CPU? Запускаю этот алгоритм-расчеты как асинхронную операцию, для этой асинхронной операции будет создан дополнительный поток, чего бы мне кто не говорил в прошлой статье, уж извините, говорить можно что угодно, но еще надо чтобы программа работала.
Код покажите, обсудим, где какой поток работает. Да, если работа на CPU - поток будет. Но если вы не создадите Thread\Task самостоятельно, то вся работа синхронно будет выполнена на вызывающем треде.
ну вот есть пример, все из той же статьи How Async/Await Really Works in C# :
using System.Diagnostics;
Time(async () =>
{
Console.WriteLine("Enter");
await Task.Delay(TimeSpan.FromSeconds(10));
Console.WriteLine("Exit");
});
static void Time(Action action)
{
Console.WriteLine("Timing...");
Stopwatch sw = Stopwatch.StartNew();
action();
Console.WriteLine($"...done timing: {sw.Elapsed}");
}
здесь для вызова action();
будет создан (взят из ТредПула) новый поток в консольном приложении, потому что она помечена как async, там далее автор показывает как подменить SynchronizationContext чтобы изменить это поведение с выделением потока. Чтобы вызывающий поток все таки дождался завершения асинхронной операции, насколько я понимаю в измененном примере поток действительно не создается. Пример как раз показывает как управлять тем будет создаваться поток для вызова функции помеченной async или нет с помощью SynchronizationContext, насколько я понимаю.
Интересно, что этот пример написан, как мне кажется, как будто специально в такой манере что-бы его поняли как можно МЕНЬше читателей! Там же вызов засунули внутрь другого вызова, надо очень внимательно вникать.
Может лучше другой пример возьмете (там же много их). А то этот про то как не надо использовать async void.
Смотрите.
Timing
... и Enter
будут выполены основным (первым) тредом, синхронно, без всякой "магии".
Дальше у нас вызов await Task.Delay(TimeSpan.FromSeconds(10));
который имитирует асинхронную работу. Если это реальная асинхронная работа (например если бы тут был запрос по сети), то CPU в этот момент будет свободен и даже первый тред может выполнять другую полезную работу, если она в приложении имеется. Конкретно Task.Delay насколько я помню опирается на планировщик и таймер системный, т.е. тоже будет действительно асинхронным. async-await и стоящая за ними стейт-машина сохранит SynchronizationContext (который в консольном приложении по умолчанию использует тред пул) и продолжит выполнение спустя 10 секунд на случайном потоке с тред пула. Это может быть как всё ещё наш первый тред, так и любой другой, который в пуле есть и не занят.
Т.е. записи ...done timing
и Exit
будут выполнены случайным потоком из тред пула, возможно первым же, возможно "вторым".
И это всё. У нас есть тред, который пишет первые записи в консоль до выполнения асинхронного вызова Task.Delay
и есть тред, который делает эту работу после вызова.
Сама задержка не требует работы тредов в дотнете - среда выполнения возьмет на себя работу по взаимодействию с ОС и её таймерами (что нужно проснуться через 10 секунд), 10 секунд никакой тред не будет молотить CPU в ожидании, а потом служебный тред будет поднят со стороны ОС, чтобы отработать после 10 секунд таймера. Да, в схеме есть служебные треды, но они выполняют небольшую служебную работу, они не молотят 10 секунд ожидая.
UPD: SynchronizationContext во всей этой схеме нужен только для одного - понять, где стоит продолжить выполнение после await-инструкции. Если явно не сказано ConfigureAwait(false), то будет попытка захвата контекста и именно в него будет передано продолжение выполнения. Контекст по умолчанию (консольный) возьмет тред с тред-пула, а контекст WPF например положит выполнение на диспатчер UI треда.
Я проверил с помощью ManagedThreadId, действительно везде тот же самый поток, то есть поток не создается!
Мне надо посмотреть-найти какой-то пример где он все таки создается или доказать что это невозможный сценарий, чтобы до конца понять закономерности - будет с чем по-упражняться в праздники.
Спасибо за критику!
В тредпуле (если он отдельно не настроен) есть несколько заранее созданных потоков, поэтому в общем случае новый поток создаваться действительно не будет.
Чтобы добиться желаемого поведения, то есть "смены" потока, можно сделать так, чтобы исходный был 100% занят во время выполнения продолжения асинхронной операции. Этого можно добиться, например, введя его в бесконечный цикл сразу после
Console.WriteLine($"...done timing: {sw.Elapsed}");
Т.е. речь про условную кофе машину, которая как раз запомнила (за счёт контекста), кто кинул монету, сварила асинхронно кофе, и вернула кофе именно тому, кто просил (вернула по контексту).
Там много вариантов, в том числе и такой. Если не читать, то посмотреть можно:
Smart Contract formal verification: Process Calculus and Modal Logics, on 4 July 2018
Вопрос: как любой сценарий с параллелизмом, конкуренцией, бисимуляцией формализовывать просто и понятно (математикой и графически) и чтобы графически была видна такая взаимосвязь. Через состояния системы - не особо хорошо видно.
Я могу Вам предложить пару вариантов схем:
или, вот здесь можно найти несколько схем:
Можно ли решить задачу реального времени без RTOS, разберем реализованную задачу
в параграфе: Временные диаграммы, задача планировщика операций
, наверно не совсем по теме, но мне кажется это в каком-то смысле решение родственной задачи.
Параллельные вычисления — Все дело в контексте-синхронизации (SynchronizationContext)