先上代码
public class TestAsyncAwaitService
{
public static async void Run()
{
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("主线程{0}:Begin ShowTimeAsync", threadId);
Console.WriteLine("主线程{0}:Begin ShowNowAsync", threadId);
var msg = ShowTimeAsync();
var aaa = ShowNowAsync();
//不使用异步执行返回值,不会被阻塞
//Console.WriteLine("msg = " + msg);
//如果要使用到异步执行的返回值,主线程就会阻塞,直到获取到异步执行结果
//Console.WriteLine("msg = " + msg.Result);
//无返回值的无法等待
Console.WriteLine("aaa = " + aaa);
//还有一种可以让主线程阻塞的办法,就是await已经await的方法,
//这个听起来很绕哈,大家可以理解为负负得正,
//一个await是异步,再一个await就是同步了,此时就会导致主线程阻塞了
var msg1 = await ShowTimeAsync();
await ShowNowAsync();
Console.WriteLine("主线程{0}:End ShowTimeAsync", threadId);
Console.WriteLine("主线程{0}:End ShowNowAsync", threadId);
}
public static async Task<string> ShowTimeAsync()
{
return await Task.Run(() =>
{
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("线程{0}开始数数...", threadId);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("线程{0}正在数数:{1}", threadId, i + 1);
Thread.Sleep(1000);
}
return string.Format("线程{0}数数完毕!", threadId);
});
}
public static async Task ShowNowAsync()
{
await Task.Run(() =>
{
var threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("线程{0}开始ShowNow...", threadId);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("线程{0}正在ShowNow,i = {1},now = {2}", threadId, i + 1,
DateTime.Now.ToString("HH:mm:ss"));
Thread.Sleep(1000);
}
Console.WriteLine("线程{0}ShowNow完毕...", threadId);
});
}
public static void RunTestForResult()
{
var watch = new Stopwatch();
Console.WriteLine("主线程begin,开始计时");
watch.Start();
Console.WriteLine("执行到a,同时开始异步计算c");
var c = CAsync(100, 88);
for (int i = 0; i < 7; i++)
{
Console.WriteLine("主线程从a执行到b需要7秒钟:{0}", i + 1);
Thread.Sleep(1000);
}
Console.WriteLine("执行b,b需要c的返回值,c的返回值(计算结果)为:{0}", c.Result);
Console.WriteLine("主线程end,共耗时{0}毫秒", watch.ElapsedMilliseconds);//10030
watch.Stop();
}
public static async void RunTestForDoubleAwait()
{
var watch = new Stopwatch();
Console.WriteLine("主线程begin,开始计时");
watch.Start();
Console.WriteLine("执行到a");
for (int i = 0; i < 7; i++)
{
Console.WriteLine("主线程从a执行到b需要7秒钟:{0}", i + 1);
Thread.Sleep(1000);
}
Console.WriteLine("执行b,b需要c的返回值,c的返回值(计算结果)为:{0}", await CAsync(100, 88));
Console.WriteLine("主线程end,共耗时{0}毫秒", watch.ElapsedMilliseconds);//17034
watch.Stop();
}
public static async Task<int> CAsync(int num, int addNum)
{
return await Task.Run(() =>
{
var id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("线程{0}开始执行求和操作:{1} + {2}", id, num, addNum);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("线程{0}在执行c操作:{1}", id, i + 1);
Thread.Sleep(1000);
}
Console.WriteLine("线程{0}计算完毕", id);
return num + addNum;
});
}
//public static async void RunNormal()
//{
// var id = Thread.CurrentThread.ManagedThreadId;
// Console.WriteLine("进入RunNormal,线程id = " + id);
// var sum = await Task.Run(() => Sum(100, 88));
// Console.WriteLine("RunNormal结束,线程id = " + id);
//}
public static int Sum(int num, int addNum)
{
var id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("线程{0}开始执行求和操作:{1} + {2}", id, num, addNum);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("线程{0}求和操作:{1}", id, i + 1);
Thread.Sleep(1000);
}
Console.WriteLine("线程{0}求和完毕", id);
return num + addNum;
}
}
个人一些理解,有不对的请指正,大神勿喷:
1.async/await方法的返回值可以有三种:void,task,task<T>,但是我推荐大家在使用的时候,只使用后两种,也就是task和task<T>,这样可以方便上端去管控执行顺序。
2.想要异步执行完毕再往下执行的方式有两种:
①:使用result,如我demo中的msg.Result,此时主线程会异步去执行msg,但是执行到msg.Result时,就会等待异步执行完毕才会继续往下执行
②:使用我1中所说的双重await,表示同步
综上所述,我个人认为的在开发中使用①好一些(个人理解),因为①分为两步:执行和等待,②只有一步:执行并等待
举个例子:a异步调用c,c执行完毕需要10秒,主线程从a执行到b需要3秒
按照①的说法使用msg.Result,那就是a调用c,c就开始执行了,这是第一步,a执行到b的时候,c已经执行了3s,此时b需要c的结果,主线程只需要再等7秒就可以,所以从a到c执行完毕,一共是3+7=10s
按照②的说法使用双重await,那就是a正常执行,耗时3秒执行到b,b需要等待c执行完,此时b = await c,c此时才开始执行,所以主线程需要等待10s,所以从a到c执行完毕,一共是3+10=13s
我已经将例子在代码中写出来了,大家可以运行参考,使用msg.Result的方法是RunTestForResult,使用双重await的方法是RunTestForDoubleAwait