首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >了解C#中的异步/等待

了解C#中的异步/等待
EN

Stack Overflow用户
提问于 2013-01-06 08:13:31
回答 5查看 50.1K关注 0票数 77

我开始学习C# 5.0中的async / await,我一点也不了解它。我不明白它怎么能用于并行性。我试过下面这个非常基础的程序:

代码语言:javascript
复制
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文章对此有所帮助。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-01-06 09:19:36

我建议你先使用我的intro to async/await,然后再使用official MSDN documentation on TAP

正如我在介绍博客文章中提到的,有几个Task成员是第三方公共关系中的遗留成员,在纯async代码中没有任何用处。new TaskTask.Start应替换为Task.Run (或TaskFactory.StartNew)。同样,应该用Task.Delay替换Thread.Sleep

最后,我建议您不要使用Task.WaitAll;您的控制台应用程序应该只在使用Task.WhenAll的单个Task上使用Wait。进行了所有这些更改后,您的代码将如下所示:

代码语言:javascript
复制
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");
    }
}
票数 69
EN

Stack Overflow用户

发布于 2016-09-08 11:37:23

了解C#任务、异步和等待

C#任务

任务类是一个异步任务包装器。Thread.Sleep(1000)可以停止线程运行1秒。而Task.Delay(1000)不会停止当前的工作。请参见代码:

代码语言:javascript
复制
public static void Main(string[] args){
    TaskTest();
}
private static void TaskTest(){
     Task.Delay(5000);
     System.Console.WriteLine("task done");
}

运行时,会立即显示“任务完成”。所以我可以假设Task中的每个方法都应该是异步的。如果我将TaskTest ()替换为Task.Run(() ),=>TaskTest()任务将不会出现,直到我在Run方法后面附加一个Console.ReadLine();。

在内部,Task类表示状态机中的线程状态。状态机中的每个状态都有若干个状态,如启动、延迟、取消和停止。

异步和等待

现在,你可能想知道,如果所有的任务都是异步的,那么Task.Delay的目的是什么?接下来,让我们通过使用async和await来真正延迟正在运行的线程

代码语言:javascript
复制
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");
}

异步告诉调用者,我是一个异步方法,不要等我。在TaskTest()中等待,请求等待异步任务。现在,在运行后,程序将等待5秒以显示任务完成文本。

取消任务

因为Task是一个状态机,所以必须有一种方法可以在任务运行时取消任务。

代码语言:javascript
复制
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");
}

现在,当程序正在运行时,可以输入"stop“来取消延迟任务。

票数 16
EN

Stack Overflow用户

发布于 2013-01-06 08:21:33

你的任务永远不会结束,因为它们永远不会开始运行。

我会用Task.Factory.StartNew来创建一个任务并启动它。

代码语言:javascript
复制
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

代码语言:javascript
复制
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");
}
票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14177891

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档