如何确定作业Async / Await的状态

时间:2013-11-14 12:02:01

标签: c# asynchronous

我从这里阅读了这条指南http://blog.stephencleary.com/2012/02/async-and-await.html

这里我有几个代码,但对我来说不是很清楚。

1)

public async Task DoOperationsInParallelAsync()
{
  Task[] tasks = new Task[3];
  tasks[0] = DoOperation0();
  tasks[1] = DoOperation1();
  tasks[2] = DoOperation2();

  // At this point, all three tasks are running in parallel.

  // Now, we await them all.
  await Task.WhenAll(tasks);
}

在上面我们创建了多个任务但是假设当所有任务都并行运行时,DoOperation2()可能首先完成,DoOperation0()和DoOperation1()完成。如果我想在控制台窗口中显示像DoOperation2()这样的消息,那么我该怎么做呢。如何在多个运行时检测到哪个任务完成。

2)当我们在 async / await 的帮助下运行任何函数时,它是作为后台线程还是前台线程运行的。

3)

public async Task<int> GetFirstToRespondAsync()
{
  // Call two web services; take the first response.
  Task<int>[] tasks = new[] { WebService1(), WebService2() };

  // Await for the first one to respond.
  Task<int> firstTask = await Task.WhenAny(tasks);

  // Return the result.
  return await firstTask;
}

我不明白为什么这个人写了等待第一个回复。

//等待第一个回复。   任务firstTask = await Task.WhenAny(tasks);

为什么第一个......为什么不是第二个因为两个任务在这里运行。

请指导我并消除我的困惑。感谢

3 个答案:

答案 0 :(得分:1)

您可以对将更新进度的每个任务使用ContinueWith方法。

因此...

foreach (var t in tasks)
{
   t.ContinueWith(Console.WriteLine("Hey I am done"));
}

答案 1 :(得分:1)

1)传入回调函数

public async Task DoOperationsInParallelAsync(Action<Task<int>> completed)
{
    var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 
    var tasks = new[] { DoOperation0(), DoOperation1(), DoOperation2() };

    var completedTasks = tasks.Select(x => x.ContinueWith(completed, uiScheduler)).ToArray();

    await Task.WhenAll(completedTasks);
}

private async void Button1_Click(object sender, EventArgs e)
{
    await DoOperationsInParallelAsync(t => {
        Label1.Text = string.Format("Task finished with {0}", t.Result);
    });
}

2)Task将在线程池上运行,除非您将其指定为长时间运行或提供TaskScheduler

3)当只有第一个结果很重要(计算是多余的或时间敏感的)时,例如从各个供应商那里获取反映相似数据的股票价格。

答案 2 :(得分:1)

  1. 因为它是一个控制台应用程序,您需要等待任务完成。以下是如何从任务返回字符串的示例:

    class WhenAny
    {
        public static async Task<string> GetFirstToRespondAsync()
        {
            // Call two web services; take the first response.
            Task<string>[] tasks = new[] { Task1(), Task2() };
    
            // Await for the first one to respond.
            Task<string> firstTask = await Task.WhenAny(tasks);
    
            // Return the result.
            return firstTask.Result;
        }
    
        private static async Task<string> Task1()
        {
            await Task.Delay(3000);
            return "Task1";
        }
    
        private static async Task<string> Task2()
        {
            await Task.Delay(1000);
            return "Task2";
        }
    }
    

    从Main函数调用它,如下所示:

    static void Main(string[] args)
    {
        var t = WhenAny.GetFirstToRespondAsync();
        t.ContinueWith((taskName) =>
            {
                string result = taskName.Result;
                Console.WriteLine("Result: " + result);
            });
    
        t.Wait();
        Console.ReadLine();
    }
    

    这应该返回首先完成的任务,您可以从Task.Result

  2. 访问该信息
  3. 等待方法本身不会创建一个额外的线程。它的作用是创建一个回调以避免阻塞当前线程(通常这用于不阻止UI线程)。

  4. WhenAny在最早完成的操作返回时返回。这并不意味着您提供的列表中的第一个。因此,上面的代码将始终显示1000,即使这是第二个任务。

  5. 为了完整性,这与WhenAll:

    是一回事
    class WhenAll
    {
    
        public static async Task<string[]> WaitForAllAsync()
        {
            // Call two web services; take the first response.
            Task<string>[] tasks = new[] { Task1(), Task2(), Task3() };
    
            // Wait for a tasks
            string[] results = await Task.WhenAll(tasks);
    
            // Return the result.
            return results;
        }
    
        private static async Task<string> Task1()
        {
            await Task.Delay(3000);
            return "Task1";
        }
    
        private static async Task<string> Task2()
        {
            await Task.Delay(1000);
            return "Task2";
        }
    
        private static async Task<string> Task3()
        {
            await Task.Delay(5000);
            return "Task3";
        }
    
    }
    

    并称之为:

    static void Main(string[] args)
    {
         var t = WhenAll.WaitForAllAsync();
         t.ContinueWith((task) =>
         {
             string[] result = task.Result;
             foreach(string taskname in result)
             {
                 Console.WriteLine("Result: " + taskname);
             }
         });
    
         t.Wait();
         Console.ReadLine();
    
    }