Задать вопрос
@Nimus2000

Как реализованы асинхронные методы c#?

Конкретно как выполняются и где.
Например, верно, что просто выделяется там 1мс времени и происходит переключение выполнения? Если так то чем отличаются от потоков.
Или там вычисляется сколько инструкций в методе, и через N инструкций вставляется точка переключения.
Или какой то другой механизм. Типа инструкции асинхроного кода смешиваются с синхронным и выполняются одновременно. Есть ли вообще такой прием(или я его первый придумал), от по идее конвеер не стопает.

Написано что есть машина состояний, только не написано, как переключается. допустим есть код вечный цикл.

Например какой то такой код, как компилируется исполняется.
int[]arr=new int[100_000];
            int k = 0;
            var t1=Task.Run(() =>
            {
                while (true)
                {
                    for (int i = 0; i < arr.Length; i++)
                    {
                        arr[i] = k;
                    }
                    k = Interlocked.Add(ref k, 1);
                }
            });


            var t2=Task.Run(() =>
            {
                while (true)
                {
                    int c = 0;
                    for (int i = 0; i < arr.Length; i++)
                    {
                        if (arr[i] != k)
                        {
                            c++;
                        }
                    }
                    Console.WriteLine(c);
                }
            });
            await Task.WhenAny(t1, t2);


Или вот например Как такой код выполнится. Могут ли эти 2 функции смешаться в одну и объеденить цикл. Ведь в идеале, можно за 1 цикл пройтись и посчиатать min/max сразу же, последовательными командами, с разными регистрами, что улучшит конвеер процесора. Или как они будут выполнятся по частям сначала 1 порция цикла, потом другая.
t1=Task.Run(() => arr.Max());
t2=Task.Run(() => arr.Min());

 await Task.WhenAll(t1, t2);
  • Вопрос задан
  • 320 просмотров
Подписаться 2 Простой 1 комментарий
Решения вопроса 1
@mvv-rus
Настоящий админ AD и ненастоящий программист
Вот вам перевод (часть первая, а всего там шесть частей) фундаменнтальной статьи по async/await одного из разрабочиков .NET в Microsoft (а именно - Stephen Toub).
Читайте и просвещайтесь.

PS Автор вопроса никак не желает считать текст выше ответом на свой вопрос - а зря. Потому что по-другому на форуме на него не ответишь - слишком много букв писать надо. Но сегодня - выходной, так что - попробую.
И самое главное, что вам следует осознать - что код асинхронного метода, который вы написали, и код машины состояний, в которой он преобразуется (и далее - транслируется в IL и компилируется в команды процессора) - это два разных кода, пусть и эквивалентных.
Если очень вкратце:
  • компилятор преобразует код асинхронного метода до неузнаваемости, в ту самую "машину состояний": класс, в котором есть метод, ее реализующий, и есть поля для данных, как нужных для работы самой машины состояний (в частности - для хранения состояния), так и для хранения локальных переменных исходного метода (да-да, в стеке они не хранятся);
  • каждый кусок исходного метода - начальный, между двумя await и завершающий - преобразуется в отдельный кусок метода машины состояний, выполняемый, когда выполнение машины состояний возобновляется в определенном состоянии; этот код производит действия, определенные в этом куске метода, и либо меняет состояние на новое значение и переходит к ожиданию (там, где в исходном асинхронном методе написан оператор await), либо завершает выполнение метода машины состояний;
  • для выполнения перехода к ожиданию используется объект awaiter'а, получаемый методом GetAwaiter() операнда операции await;
  • перед переходом к ожиданию проверяется возможно продолжение без ожидания, если это возможно (метод IsCompleted() awaiter'а возвращает true), то ожидания не происходит, а возобновляется выполнение машины состояний уже для нового состояния;
  • запуск ожидания происходит во внешнем относительно асинхронного метода коде - в объекте awaiter'а;
  • и при завершении метода машины состояний, и при запуске ожидания метод машины состояний возвращает управление в код, который вызвал в этот раз метод машины состояний (для одного вызова асинхронного метода вызовов метода машины состояний может быть много, см. дальше);
  • первый возврат из метода машины состояний происходит в вызывающий метод, он возвращает объект задачи, позволяющий отследить в вызывающем методе завершение работы машины состояний ( и тут есть нюанс, связанный с возвращением ValueTask, а не Task);
  • при окончательном (а не при запусе ожидания) выходе из метода машины состояний этот возвращенный объект задачи завершается;
  • после завершения ожидания метод машины состояний вновь вызывается: в типичном случае - в свободном потоке из пула потоков, но возможны варианты (какие - курить тему Synchronization Context); и он продолжает свое выполнение для нового состояния

Это - максимально урезанное описание работы асинхронного метода.
Если вы смогли из этого описания понять ответ на ваш первый вопрос - хорошо. Если нет - читайте статьи(ссылка выше), или книги (лично я рекомендую главу про асинхронные меотоды из книги Рихтера "CLR via C#").
Касательно второго вопроса. Задачи, выполнение которых ожидает асинхронный метод, будут выполняться совершенно параллельно, каждая - в своем потоке из пула, возможно - на разных ядрах/процессорах). А асинхронный метод в это время не будет выполняться совсем: поток в котором он выполнялся, будет дальше выполнять код после его вызова в вызвавшем его методе (или код, возвращий поток в пул, если это был вызов машины состояний после ожидания). А после завершения обеих этих задач выполнение метода машины состояний, в который был преобразован асинхроннный метод, будет возобновлено и задача, которую возвратил асинхронный метод, будет завершена.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы