2.foreach使用ef操作,使用方式注意:
List<string> l1 = new List<string>(); l1.Add("1"); l1.Add("2"); l1.Add("3"); l1.Add("4"); foreach (var ss in l1) { User models = await repo.GetAll<User>().SingleOrDefaultAsync(x => x.Account == ss); } //l1.ToList().ForEach(q=>{ // User models = await repo.GetAll<User>().SingleOrDefaultAsync(x => x.Account == q); //});//这样写会报上下文不能被不同线程访问的异常
1.实践代码全记录:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace await_测试 { class Program { static void Main(string[] args) { testc(); Console.Read(); } //async具有僵尸病毒般的传染性,async 会感染周围的代码,直到顶层。其实我们只需要顺其自然,让所有代码都传染上异步特性即可。 //如果我们使用Task.Wait 或者Task.Result去试图阻塞async 的传播,往往便会自找苦吃。 //这个往往是刚接触async 异步的人最容易犯的错误,这样往往会导致死锁。互相等待。 static async void testc() { ////----写法1. //Stopwatch sw = new Stopwatch(); //sw.Start(); //var d1 = delay10();//立刻执行,等待取回结果 //var d2 = delay20();//立刻执行,等待取回结果 //var d3 = delay30();//立刻执行,等待取回结果 ////依次取结果,取结果时间很短 //await d1;// 单条语句的确没有意义,但类似本场景多条语句的话,异步并发执行的优势就出来了。总耗时是最长耗时的那个值。 //await d2;// 第一个执行完,取不取结果是另一回事。 //await d3;// 并发执行,【2】需要获得值的时候,禁用Task.Wait or Task.Result 用 await,防止 异常信息以及防止死锁 //sw.Stop(); //Console.WriteLine("结束"); //Console.WriteLine("耗时:" + sw.ElapsedMilliseconds); ////结论:互不影响,同时进行,耗时约25秒 //----写法11. Stopwatch sw = new Stopwatch(); sw.Start(); var d1 = delay10();//立刻执行,等待取回结果 var d2 = delay20();//立刻执行,等待取回结果 var d3 = delay30();//立刻执行,等待取回结果 //依次取结果,取结果时间很短 Console.WriteLine( d1.Result);// 单条语句的确没有意义,但类似本场景多条语句的话,异步并发执行的优势就出来了。总耗时是最长耗时的那个值。 Console.WriteLine( d2.Result);// 第一个执行完,取不取结果是另一回事。 Console.WriteLine( d3.Result);// 并发执行,【2】需要获得值的时候,禁用Task.Wait or Task.Result 用 await,防止 异常信息以及防止死锁 sw.Stop(); Console.WriteLine("结束"); Console.WriteLine("耗时:" + sw.ElapsedMilliseconds); //结论:互不影响,同时进行,耗时约25秒 ////----写法2. //Stopwatch sw = new Stopwatch(); //sw.Start(); //await delay10();//线性执行,线性取回结果 //await delay20();//线性执行,线性取回结果 //await delay30();//线性执行,线性取回结果 //sw.Stop(); //Console.WriteLine("耗时:" + sw.ElapsedMilliseconds); ////结论:耗时是43秒,线性按行执行,总耗时大于三个线程耗时之和。 ////----写法3. //Stopwatch sw = new Stopwatch(); //sw.Start(); //Task t1 = delay10();//立刻执行, //Task t2= delay20(); //立刻执行, //Task t3 = delay30();//立刻执行, //Task[] tk = { t1, t2, t3 }; //await Task.WhenAll(tk); //sw.Stop(); //Console.WriteLine("耗时:" + sw.ElapsedMilliseconds); //////结论:互不影响,同时进行,耗时约25秒 //----写法4. //Stopwatch sw = new Stopwatch(); //sw.Start(); //Task t1 = delay10();//立刻执行, //Task t2 = delay20(); //立刻执行, //Task t3 = delay30();//立刻执行, //Task[] tk = { t1, t2, t3 }; //Task.WaitAll(tk); //注意:【1】需要等待所有任务完成 禁用Task.WaitAll 用 await Task.WhenAll,防止 异常信息以及防止死锁 //http://www.cnblogs.com/bnbqian/p/4513192.html //sw.Stop(); //Console.WriteLine("耗时:" + sw.ElapsedMilliseconds); //////结论:互不影响,同时进行,耗时约25秒 ////总结: 进化过程:Thread+线程同步信号量 -> Task -> async&await } static async Task<string> delay10() { Task<string> t = new Task<string>(() => { Thread.Sleep(25000);//小失误。需要等待请用:Task.Delay(),禁用Thread.Sleep,防止 异常信息以及防止死锁 return "25000"; }); t.Start(); string tr = await t; return tr;// Console.WriteLine(tr); } static async Task<string> delay20() { Task<string> t = new Task<string>(() => { Thread.Sleep(10000); return "10000"; }); t.Start(); string tr = await t; return tr;// Console.WriteLine(tr); } static async Task<string> delay30() { Task<string> t = new Task<string>(() => { Thread.Sleep(3600); return "3600"; }); t.Start(); string tr = await t; return tr;// Console.WriteLine(tr); } } }
2.实践笔记:
1.无论方法是同步还是异步都可以用async关键字来进行标识,因为用async标识只是显示表明在该方法内可能会用到await关键字使其变为异步方法,而且将该异步方法进行了明确的划分,只有用了await关键字时才是异步操作,其余一并为同步操作。
2.当用async标识方法时只是显示告诉编译器在该方法中await关键字可能会被用到,当执行到await关键字开始处于挂起的状态知道异步动作执行完成才恢复。
3.用async标识方法并不会影响方法运行完成是否是同步或者异步,相反,它能够将方法划分成多块,有可能有些在异步中运行,以至于这些方法是异步完成的,而划分异步和同步方法的边界就是使用await关键字。也就是说如果在方法中未用到await关键字时则该方法就是一整块没有所谓的划分,会在同步中运行,在同步中完成。