await/async语法
用同步的方式写异步回调
C#5 (.NET4.5) 引入的语法糖 C#7.1,Main入口也可以 C#8.0,可以使用异步流await foreach和可释放对象 await using
1 async 是用来修饰方法,如果单独出现,方法会警告,没有什么作用 2 await在方法体内部,只能放在async修饰的方法内,必须放在task前面 3 async/await方法里面如果没有返回值,默认返回一个Task,或者void(推荐用Task,而不是void,因为这样才能await/wait) 4 带async+await后,返回值要多一层Task<>
返回值void函数
主线程到await这里就返回了,执行主线程任务; 同时task的子线程就开始工作,直到Task完成,然后继续后续任务(后续任务的线程ID不一定是这个子线程,可以是子线程,也可以是其他线程,还可以是主线程); 效果上等价于continuewith。
private static async void NoReturn()
{
Console.WriteLine($"NoReturn Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
TaskFactory taskFactory = new TaskFactory();
Task task = taskFactory.StartNew(() =>
{
Console.WriteLine($"NoReturn Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(3000);
Console.WriteLine($"NoReturn Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
});
await task;
Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}
返回值Task函数
无返回值 async Task == async void; Task和Task< T>能够使用await, Task.WhenAny, Task.WhenAll等方式组合使用。Async Void 不行。
private static async Task NoReturnTask()
{
Console.WriteLine($"NoReturnTask Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
Task task = Task.Run(() =>
{
Console.WriteLine($"NoReturnTask Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
Console.WriteLine($"NoReturnTask Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
});
await task;
Console.WriteLine($"NoReturnTask Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}
返回值Task的函数
private static async Task<long> SumAsync()
{
Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
long result = 0;
await Task.Run(() =>
{
for (int k = 0; k < 10; k++)
{
Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
}
for (long i = 0; i < 999_999_999; i++)
{
result += i;
}
});
Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
await Task.Run(() =>
{
for (int k = 0; k < 10; k++)
{
Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
}
for (long i = 0; i < 999999999; i++)
{
result += i;
}
});
Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
await Task.Run(() =>
{
for (int k = 0; k < 10; k++)
{
Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
}
for (long i = 0; i < 999999999; i++)
{
result += i;
}
});
Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
调用如下:
Task<long> t = SumAsync();
Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
long lResult = t.Result;
没有Async和Await的函数
private static Task<int> SumFactory()
{
Console.WriteLine($"SumFactory 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
TaskFactory taskFactory = new TaskFactory();
Task<int> iResult = taskFactory.StartNew<int>(() =>
{
Thread.Sleep(3000);
Console.WriteLine($"SumFactory 123 Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
return 123;
});
Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
return iResult;
}
其他
适合场景
跟第三方交互的(非托管资源,经常有async版本):
- 数据库openAsync-Redis
- Web请求-Api
- 文件读取
Await为什么能提升吞吐—只负责发命令—然后就忙别的去了—不需要等待—事儿完成前就不浪费资源—完成后再来线程处理—这里还能复用
不适合场景
服务器本地计算(CPU密集型,托管资源)
反而可能影响性能,但是用了没啥事儿
总结
await/async是语法糖,同步方式写异步,增加系统吞吐量,一用到底,Web开发推荐
|