вторник, 10 января 2017 г.

C# async/await - шапошное знакомство

(не очень информативно получилось, если честно)

во все нюансы этой штуки я не вник. почитал документацию от Microsoft - много информации, общая картина в голове не сложилась.

прочел https://habrahabr.ru/post/139734/ - общее представление появилось. хотя, еще много нюансов осталось неизученными.

эта фича дает возможность запускать асинхронно метод в фоновом потоке, а когда она закончится - код, использующий результат выполнения асинхронного метода, вызывается опять в вызывающем потоке (типа, сработало событие "поток закончен").
при чем, код очень похож на аналогичный код, выполняемый синхронно в одном потоке.

это прикольно для GUI-приложений, т.к. облегчает вызов обработки долгих операций в фоновом режиме

то есть, нажали кнопку - в обработчике в первой строке кода кнопка заблокировалась, следующей строчкой прописывается вызов асинхронного метода, следующей строчкой - кнопка разблокируется, результат вычисленицй куда-нить выводится. а по факту, когда дело доходит до второй строчки - создается и запускается поток, в котором вызвается асинхронный метод, после чего в первом потоке происходит выход из обработчика нажатия ()

профит - во время выполнения длительной операции GUI-поток не зависает, интерфейс продолжает реагировать на действия пользователя

написал тестовое приложеньице:

        static void Main(string[] args)
        {

            Log("привет!");
            SomeOperation();    //тут - предупреждение компилятора, что операция используется без слова await, и будет запущена асинхронно
            Log("пока!");

            Console.WriteLine("DONE");
            Console.ReadKey();
        }
        async static Task SomeOperation()
        {
            Log("Запускаем фиктивный пустой таск");
            
            await Task.Run(()=> {});
            Log("и весь дальнейший код будет выполняться уже в фоновом потоке");
            Log("начинаем операцию по ожиданию...");
            Thread.Sleep(1500);
            Log("закончили");
        }

        static void Log(string s)
        {
            Console.WriteLine($"{s} - поток: {Thread.CurrentThread.ManagedThreadId}");
        }
    }


вывод:
привет! - поток: 9
Запускаем фиктивный пустой таск - поток: 9
пока! - поток: 9
DONE
и весь дальнейший код будет выполняться уже в фоновом потоке - поток: 10
начинаем операцию по ожиданию... - поток: 10
закончили - поток: 10


в общем, полной ясности нет, но штука интересная. если доведется с потоками колдовать - еще поизучаю

UPD:  все еще нет полной ясности. но, кажется, эта тема - не для асинхронной обработки и паралеллизма. а для ситуаций, когда определенный поток является ценным ресурсом, и не хочется выполнять на нем длительные операции. например основной поток GUI-приложения, или поток из пула потоков на вэб-сервере, где есть настройка, задающая максимальное число выполняемых одновременно потоков из пула (или как-то так)