C#中对异步⽅法及异步lambda表达式这篇⽂章的⽬的并不是系统地介绍C#中的await、async关键字,⽽是针对我遇到的⼀些问题进⾏记录。
背景
await / async
C#中可以⽤async标识⽅法,表⽰这个⽅法是异步的。异步⽅法的返回值必须是void、Task或者Task<T>。例如:public static async Task<int> Method(int i)
{
await Task.Delay(1000);
return i;
}
1
2
3
4
5
⽤async修饰的lambda表达式
我们可以⽤async修饰lambda表达式,标识这个表达式为异步。
Func<Task<HttpResponseMessage>> lambda = async () =>
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("www.bing/");
return response;
}
};
1
2
3
4
5
6
7
8
可以看到,⽤async修饰以后,返回值也变为Task<HttpResponseMessage>。
async标记只是针对⽅法内部,外部只关⼼返回值类型。
异步⽅法返回的时间
异步⽅法在遇到await关键字之后就会返回。例如下⾯的代码:
private static Stopwatch stopwatch;
static void Main(string[] args)
{
stopwatch = Stopwatch.StartNew();
Task task = MethodAsync();
Console.WriteLine($"Main: {stopwatch.ElapsedMilliseconds}");
}
public static async Task MethodAsync()
{
Console.WriteLine("Enter method.");
Task.Delay(500).Wait();
Console.WriteLine($"Method will return: {stopwatch.ElapsedMilliseconds}");
await Task.Delay(1000);
Console.WriteLine($"End of method: {stopwatch.ElapsedMilliseconds}");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
MethodAsync()⽅法会在遇到await时返回。于是就有了如下输出:
Enter method.
Method will return: 542
Main: 544
1
2
3
Task类的⼀些⽅法
Task.Run(Action action)
我们可以⽤Task.Run(Action action)来启动⼀个任务。
static void Main(string[] args)
{
stopwatch = Stopwatch.StartNew();
var task = Task.Run(MethodAsync);
task.Wait();
Console.WriteLine($"Main: {stopwatch.ElapsedMilliseconds}");
}
1
2
3
4
5
6
7
其中MethodAsync就是上⾯定义的⽅法。
可以推测,MethodAsync执⾏到第⼀个await就会返回。Wait()⽅法也会执⾏完毕。整段程序执⾏500多毫秒就应该结束。
让我们运⾏⼀下。
Enter method.
Method will return: 544
End of method: 1546
Main: 1547
1
2
3
4
奇怪,MethodAsync返回不久,整个程序就应该结束才是,为什么等待了⼀秒多,直到MethodAsync全部执⾏完?
Task.Run(Func<Task> function)
原来,Task.Run那⾥实际调⽤的是Task.Run(Func<Task> function)这个重载。这个重载返回的Task对象,我们在调⽤其Wait()成员⽅法时会等待function返回的Task对象执⾏结束。我认为应该是为了⽅便这种情况。
await Task.Run(async () =>
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("www.bing/");
return response;
}
});
1
2
3
4await和async使用方法
5
6
7
8
在这段代码中,正是由于调⽤的是Task.Run(Func<Task> function)这个重载,才保证了请求完成后才会继续执⾏后⾯的代码。System.Threading.Tasks.Parallel类的情况
System.Threading.Tasks.Parallel类提供了⾮常⽅便的并发执⾏循环的⽅法。
Parallel.For(0, 10, i => Console.WriteLine(i));
1
输出
2
6
4
5
8
9
7
3
1
1
2
3
4
5
6
7
8
9
10
再试试
Parallel.For(0, 10, async i =>
{
await Task.Delay(1000);
Console.WriteLine(i);
});
1
2
3
4
5
输出
1
是的,输出没有任何内容。
原因是,Parallel和Task不⼀样,它并不会等待返回的Task,⽽是在⽅法返回后就结束。
所以,如果想确保异步⽅法完全完成,必须改为同步。
Parallel.For(0, 10, i =>
{
Task.Delay(1000).Wait(); Console.WriteLine(i); });
1
2
3
4
5
输出
8
4
6
2
1
7
5
3
9
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论