异步
异步由异步方法和调用方法两部分组成,其中异步方法中包含至少一个的 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> 对象,同时异步方法开始执行
Tasktsk.Result
属性来获取结果,此时如果异步工作已经完成,会返回结果;如果未完成,会阻塞当前线程直到异步工作完成。
- 异步方法的参数不能为 out 或者 ref 关键字。
- 按照惯例,异步方法的名称以 Async 结尾。
返回类型
异步方法的返回类型可以是 void、Task、Task
Task 类型
如果想要异步方法返回一个值,可以使用 Task
返回值必须是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.Run()
Task.Run() 会在不同的线程中执行异步方法,而不是在当前线程中执行。
在默认情况下,Task 使用线程池中的线程来执行。线程池是一组预先创建的线程,可以重复使用以执行多个任务。如果线程池中有可用的线程,则 Task 可能会在其中的某个线程上执行。如果线程池中没有可用的线程,则会创建新的线程来执行 Task。
Task.Run() 需要传入一个 Func
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