Может кто-нибудь, пожалуйста, объясните async/wait?
Я начинаю узнавать об async/await в С# 5.0, и я вообще этого не понимаю. Я не понимаю, как его можно использовать для parallelism. Я пробовал следующую очень базовую программу:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Task task1 = Task1();
Task task2 = Task2();
Task.WaitAll(task1, task2);
Debug.WriteLine("Finished main method");
}
public static async Task Task1()
{
await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
Debug.WriteLine("Finished Task2");
}
}
}
Эта программа просто блокируется при вызове Task.WaitAll()
и никогда не заканчивается. Может кто-нибудь, пожалуйста, объясните мне, почему? Я уверен, что я просто пропустил что-то простое или просто не имею правильной ментальной модели этого, и ни одна из блогов или статей MSDN, которые там есть, помогает.
Ответы
Ответ 1
Я рекомендую вам начать с intro до async
/await
и следить за официальная документация MSDN по TAP.
Как я упоминал в своем блоге в блоге, есть несколько членов Task
, которые являются задержками с TPL и не используют чистый код async
. new Task
и Task.Start
следует заменить на Task.Run
(или TaskFactory.StartNew
). Аналогично, Thread.Sleep
следует заменить на Task.Delay
.
Наконец, я рекомендую вам не использовать Task.WaitAll
; ваше консольное приложение должно просто Wait
на одном Task
, которое использует Task.WhenAll
. Со всеми этими изменениями ваш код будет выглядеть так:
class Program
{
static void Main(string[] args)
{
MainAsync().Wait();
}
public static async Task MainAsync()
{
Task task1 = Task1();
Task task2 = Task2();
await Task.WhenAll(task1, task2);
Debug.WriteLine("Finished main method");
}
public static async Task Task1()
{
await Task.Delay(5000);
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await Task.Delay(10000);
Debug.WriteLine("Finished Task2");
}
}
Ответ 2
Ваши задачи никогда не заканчиваются, потому что они никогда не запускаются.
Я бы Task.Factory.StartNew
создал задачу и запустил ее.
public static async Task Task1()
{
await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
Debug.WriteLine("Finished Task2");
}
Как побочная заметка, если вы действительно просто пытаетесь сделать паузу в асинхронном методе, нет необходимости блокировать весь поток, просто используйте Task.Delay
public static async Task Task1()
{
await Task.Delay(TimeSpan.FromSeconds(5));
Debug.WriteLine("Finished Task1");
}
public static async Task Task2()
{
await Task.Delay(TimeSpan.FromSeconds(10));
Debug.WriteLine("Finished Task2");
}
Ответ 3
Async и ждут маркеры, которые отмечают позиции кода, из которых элемент управления должен возобновиться после завершения задачи (потока).
Вот подробное видео youtube, которое объясняет концепцию демонстративным образом http://www.youtube.com/watch?v=V2sMXJnDEjM
Если вы хотите, вы также можете прочитать эту статью coodeproject, которая объясняет это более наглядным образом.
http://www.codeproject.com/Articles/599756/Five-Great-NET-Framework-4-5-Features#Feature1:- "Async" и "Await" (Codemarkers)
Ответ 4
Понять задачу С#, асинхронно и ждать
Задача С#
Класс задачи - это асинхронная оболочка задачи. Thread.Sleep(1000) может остановить поток, выполняющийся в течение 1 секунды. Хотя Task.Delay(1000) не остановит текущую работу. См. Код:
public static void Main(string[] args){
TaskTest();
}
private static void TaskTest(){
Task.Delay(5000);
System.Console.WriteLine("task done");
}
При запуске "задание выполнено" будет отображаться немедленно. Поэтому я могу предположить, что каждый метод из Task должен быть асинхронным. Если я заменю TaskTest() на Task.Run(() = > TaskTest()) выполненная задача не будет отображаться вообще, пока я не добавлю консоль. ReadLine(); после метода Run.
Внутренне класс Task представляет состояние потока в машине состояния. Каждое состояние в государственной машине имеет несколько состояний, таких как "Пуск", "Задержка", "Отмена" и "Стоп".
асинхронный и ожидающий
Теперь вы можете задаться вопросом, является ли все задачи асинхронными, какова цель Task.Delay? next, пусть действительно задерживает текущий поток с помощью async и ждет
public static void Main(string[] args){
TaskTest();
System.Console.WriteLine("main thread is not blocked");
Console.ReadLine();
}
private static async void TaskTest(){
await Task.Delay(5000);
System.Console.WriteLine("task done");
}
async tell caller, я асинхронный метод, не ждите меня. ожидание внутри TaskTest() требует ожидания асинхронной задачи. Теперь, после запуска, программа будет ждать 5 секунд, чтобы отобразить выполненный текст.
Отменить задачу
Поскольку Task является конечным автоматом, должен быть способ отменить задачу во время выполнения задачи.
static CancellationTokenSource tokenSource = new CancellationTokenSource();
public static void Main(string[] args){
TaskTest();
System.Console.WriteLine("main thread is not blocked");
var input=Console.ReadLine();
if(input=="stop"){
tokenSource.Cancel();
System.Console.WriteLine("task stopped");
}
Console.ReadLine();
}
private static async void TaskTest(){
try{
await Task.Delay(5000,tokenSource.Token);
}catch(TaskCanceledException e){
//cancel task will throw out a exception, just catch it, do nothing.
}
System.Console.WriteLine("task done");
}
Теперь, когда программа запущена, вы можете ввести "стоп", чтобы отменить задачу "Задержка".