Skip to content

异步

异步由异步方法和调用方法两部分组成,其中异步方法中包含至少一个的 await 关键字。

异步方法:

public static async Task<int> CalculateSumAsync(int a, int b)
{
    int sum = await Task.Run(() => GetSum(a, b)); # await 关键字,表示这里是异步操作
    return sum;
}

调用方法:

Task<int> tsk = CalculateSumAsync(1, 2); # 这里调用了异步方法,会立刻返回一个 Task<int> 对象,同时异步方法开始执行

Task 是一个异步操作的占位符对象,他会在异步方法中立刻返回,然后再开始异步工作。当调用 tsk.Result 属性来获取结果,此时如果异步工作已经完成,会返回结果;如果未完成,会阻塞当前线程直到异步工作完成。

  • 异步方法的参数不能为 out 或者 ref 关键字。
  • 按照惯例,异步方法的名称以 Async 结尾。

返回类型

异步方法的返回类型可以是 void、Task、Task 三种类型。

Task 类型

如果想要异步方法返回一个值,可以使用 Task 类型,其中 T 为返回值的类型。调用方法通过task的Result属性来获取返回值。

返回值必须是T类型,或者可以隐式转换为T类型。

Task<int> value = CalculateSumAsync(1, 2);
Console.WriteLine(value.Result); 

Task 类型

如果异步方法不需要返回值,但是需要检查这个方法的执行状态。可以使用 Task 类型。调用方法通过task的Wait()方法来等待异步方法执行完成。

即使异步方法中有return 语句,也不会返回值。

Task myTask = CalculateSumAsync(1, 2);
myTask.Wait();

void 类型

如果只想执行一个异步方法,不需要返回值,也不需要检查执行状态,可以使用 void 类型(调用并忘记 fire and forget)。

即使异步方法中有return 语句,也不会返回值。

控制流

在异步方法中,遇到第一个 await 关键字之前的部分会同步执行(在调用处阻塞)。

在遇到 await 关键字时,如果返回类型为 Task 或者 Task,会产生一个Task类型的对象,然后立刻返回到调用方法处,异步方法继续执行,完成 await 关键字下面的工作(可能还有其他 await 语句),然后遇到 return 语句,更新Task的属性,退出。

Task.Run()

Task.Run() 会在不同的线程中执行异步方法,而不是在当前线程中执行。

在默认情况下,Task 使用线程池中的线程来执行。线程池是一组预先创建的线程,可以重复使用以执行多个任务。如果线程池中有可用的线程,则 Task 可能会在其中的某个线程上执行。如果线程池中没有可用的线程,则会创建新的线程来执行 Task。

Task.Run() 需要传入一个 Func 的委托,返回值为 T 类型。

public int Get10()
{
    return 10;
}

Func<int> ten = new Func<int>(Get10);

int a = await Task.Run(ten);

int b = await Task.Run(() => Get10());

int c = await Task.Run(() => {return 10;});

Console.WriteLine($"a:{a}, b:{b}, c:{c}");

// a:10, b:10, c:10

ref