@DarkByte2015

Как сделать асинхронность без await?

Как быть если метод должен быть асинхронным (async Task), но в нем совсем негде вставить await? Причем не хочется плодить потоки Task.Run-ом. Единственное что в голову приходит это сделать await Task.Delay(1). Т.е. одну миллисекунду никто не заметит, но метод уже выйдет асинхронным. Но это имхо очень корявое решение. Есть ли какие то еще варианты?
  • Вопрос задан
  • 855 просмотров
Решения вопроса 1
Пригласить эксперта
Ответы на вопрос 2
Trixon
@Trixon
Суровый ASP.NET веб-разработчик
Вы вызываете await на методе, помеченном async, назовём его MethodAsync.
В методе MethodAsync, в точке, где вызывается другой асинхронный метод вместе с await, компилятор разбивает метод MethodAsync на две части. До await и после await.
Всё, что было до await, выполняется в контексте первичного потока.
Операция, помеченная await (в методе MethodAsync) + всё, что было после неё, выполняется в контексте вторичного потока.

Вызывая await Task.Delay, Вы всё равно заимствуете вторичный поток из пула. Можно сказать, это то же самое, что вызвать await Task.Run, поместив туда часть метода, которая находилась бы после await Task.Delay.

Вот код, пробуйте:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static async Task MethodDelayAsync()
        {
            Console.WriteLine("1. MethodDelayAsync: before await thread id: {0}", Thread.CurrentThread.ManagedThreadId);

            await Task.Delay(1000);

            Console.WriteLine("2. MethodDelayAsync: after await thread id: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        
        static async Task MethodTaskRunAsync()
        {
            Console.WriteLine("1. MethodTaskRunAsync: before await thread id: {0}", Thread.CurrentThread.ManagedThreadId);

            await Task.Run(() =>
            {
                Console.WriteLine("Asynchronous operation in MethodTaskRunAsync in thread id: {0}",
                    Thread.CurrentThread.ManagedThreadId);
            });

            Console.WriteLine("2. MethodTaskRunAsync: after await thread id: {0}", Thread.CurrentThread.ManagedThreadId);
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Start Main in thread id: {0}", Thread.CurrentThread.ManagedThreadId);

            //MethodDelayAsync();
            MethodTaskRunAsync();

            Console.WriteLine("End Main in thread id: {0}", Thread.CurrentThread.ManagedThreadId);
            
            Console.Read();
        }
    }
}


Раскомментировав MethodTaskRunAsync:
Start Main in thread id: 1
1. MethodTaskRunAsync: before await thread id: 1
Asynchronous operation in MethodTaskRunAsync in thread id: 3 -- вторичный поток из пула.
End Main in thread id: 1
2. MethodTaskRunAsync: after await thread id: 3 -- вторичный поток из пула.

Раскомментировав MethodDelayAsync:
Start Main in thread id: 1
1. MethodDelayAsync: before await thread id: 1
End Main in thread id: 1
2. MethodDelayAsync: after await thread id: 4 -- вторичный поток из пула.

А это значит, что всё происходит ровно так, как сказано мною выше.
Ответ написан
@zzzzzzerg
Task.Run добавить задачу в очередь, которая выполняется на пуле потоков, т.е. у вас не будет дополнительного создания поток.
Кроме того, я не нашел в документации Task.Join, поэтому не понимаю, что вы имеете в виду.
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы