1、saycn和await的定义
资料:https://www.jb51.net/article/237968.htm
await operator - C# reference | Microsoft Docs
async - C# Reference | Microsoft Docs
看了一遍,关于这个async这个连接说的比较详细
1.1、async
微软文档:使用 async
修饰符可将方法、lambda 表达式或匿名方法指定为异步。
使用 async 修饰的方法,称为异步方法。
Use the
async
modifier to specify that a method, lambda expression, or anonymous method is asynchronous. If you use this modifier on a method or expression, it's referred to as an async method.
1.2、await
微软文档:await
运算符暂停对其所属的 async
方法的求值,直到其操作数表示的异步操作完成。
异步操作完成后,await
运算符将返回操作的结果(如果有)。
The
await
operator suspends evaluation of the enclosing async method until the asynchronous operation represented by its operand completes. When the asynchronous operation completes, theawait
operator returns the result of the operation, if any. When theawait
operator is applied to the operand that represents an already completed operation, it returns the result of the operation immediately without suspension of the enclosing method. Theawait
operator doesn't block the thread that evaluates the async method. When theawait
operator suspends the enclosing async method, the control returns to the caller of the method.
2、await和asycn是一对
这一对标签的目的是为了将某个方法直接标注为异步,具体用法如下
2.1、有asycn就必须有await
当将某个方法的头部加上asycn task<>时,就意味着在说明这个方法可以当作一个task来用,具体来看这样一个例子:
下面的这一段代码使用了async和await这两个标记将一个普通的同步方法改为了异步方法,然后这个异步方法就可以看成是一个task.run()直接使用具体方法和之前的task是一样的。
static void Main(string[] args)
{
System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
st.Start();
Task.Delay(1000);
Task tt= async_Test_1();
long time0 = st.ElapsedMilliseconds;
Task ttt= async_Test_1();
long time1 = st.ElapsedMilliseconds;
tt.Wait();
ttt.Wait();
long tttt = st.ElapsedMilliseconds;
Console.WriteLine("\ntime0="+time0.ToString()+"\ntime1="+time1.ToString());
Console.WriteLine(tttt.ToString());
}
static void Test_1()
{
int time = new Random().Next(2, 6);
Thread.Sleep(TimeSpan.FromSeconds(time));
Console.WriteLine(time);
}
static async Task async_Test_1()
{
await Task.Run(() => Console.WriteLine("I'm await "));
int time = new Random().Next(2, 6);
Thread.Sleep(TimeSpan.FromSeconds(time));
Console.WriteLine(time);
}
但应该注意的是,只有方法体内部有一个await后才可以真正实现异步调用,否则这个方法会被当成是一个同步方法来使用,如下图。这样的代码可以运行,但它会是一个同步方法,就和没改过一样。
2.2、await在使用过程中的注意点
还是上面的那段代码,我对被改的异步方法asycn_test_1做一点小的改动,我将
await Task.Run(() => Console.WriteLine("I'm await "));这一句挪到最下边。
static async Task async_Test_1()
{
// await Task.Run(() => Console.WriteLine("I'm await "));
//上面的那一句挪到下边去
int time = new Random().Next(2, 6);
Thread.Sleep(TimeSpan.FromSeconds(time));
Console.WriteLine(time);
await Task.Run(() => Console.WriteLine("I'm await "));
}
这时输出值中的t1和t2的开始时间会有非常大的变化,根据时间推断t1和t2任务变成了先后执行,而不是我想要的异步执行,输出结果如下图
于是可以推断,await起的作用是给异步方法一个标记点,告诉程序从这里开始线程t1开始异步执行,程序返回主线程开始执行t2,当t2也到了这个标记点,线程t2也开始独立运行,程序继续回到了主线程。为了说明这一点,来看一个新的程序:
static void Main(string[] args)
{
System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
st.Start();
//await Task.Delay(0);
long begin = st.ElapsedMilliseconds;
Task t1= async_Test_1();
long time0 = st.ElapsedMilliseconds;
Task t2= async_Test_1();
long time1 = st.ElapsedMilliseconds;
t1.Wait();
long t1FinishTime = st.ElapsedMilliseconds;
t2.Wait();
long t2FinishTime = st.ElapsedMilliseconds;
Console.WriteLine(" 开始时间:"+begin.ToString());
Console.WriteLine(" t1开始执行时间:"+time0.ToString());
Console.WriteLine(" t2开始执行时间:"+time1.ToString());
Console.WriteLine(" t1结束时间:" + t1FinishTime.ToString());
Console.WriteLine(" t2结束时间:" + t2FinishTime.ToString());
}
static async Task async_Test_1()
{
//await Task.Run(() => Console.WriteLine("I'm await "));
int time = new Random().Next(1, 3);
Thread.Sleep(TimeSpan.FromSeconds(time));
Console.WriteLine(" 刚刚等了{0}000mss。",time);
await Task.Run(() => Console.WriteLine(" I'm await "));
int time2 = new Random().Next(4, 6);
Console.WriteLine(" 这条线程开始独立运行了,将运行{0}000ms。",time2);
Thread.Sleep(TimeSpan.FromSeconds(time2));
Console.WriteLine(" {0}000ms运行完毕。",time2);
}
运行结果如下:
对比一下时间差,会发现开始独立运行后时间上是有重复的,这说明在开始独立运行后程序分别开始了异步执行。关于这个问题,微软文档上也有相应的说明:
An async method runs synchronously until it reaches its first
await
expression, at which point the method is suspended until the awaited task is complete. In the meantime, control returns to the caller of the method, as the example in the next section shows.
3、总结
于是我总结了这样几条关于async和await的总结:
(1)、async说明某个方法可以当作异步方法
(2)、在方法头部加asycn时应该记得将该方法返回值改为对应的Task,具体来说,就是 void->task,
int->task<int>,
Tuple<...>改为Task<Tuple<.....>>,
依次类推。
(3)、await必须要加,加了后await引导的语句要执行后才能往下执行,同时第一个await语
句后的程序会开始异步执行。如果需要在一开始就异步执行,那么在一开始加 await
Task.Delay(0);