.NET Core 核心知识点(二)

Task.WhenAll、异步与多线程、异步编程注意点、异步与yield


  • 异步编程和多线程

        多线程只是异步的一种实现方式,异步编程也可是单一线程,比如async方法中的await执行时,当前线程会被线程池收走,等方法await的方法执行完成时,线程池会调度一个新的线程过来执行下面的逻辑;此过程虽然切换了线程,但是同一时间运行的线程只有一个,并不是多线程。

  • Task.WhenAll
  • Task类有两个静态方法,WhenAny()和WhenAll();WhenAny() 代表所有异步task任务中只要有一个执行完成,就执行;WhenAll是代表必须等待所有异步task任务执行完,才走后面的逻辑。一般项目中WhenAll()方法用的比较多。
  • Task.WhenAll()等待所有的Task执行完成,但是这些Task不是同步顺序执行的,而是异步一起执行的,开启多个线程异步执行,可以加快程序效率,如果项目中遇到耗时的重复代码时,可以考虑用Task.WhenAll;

比如下面两个例子:

第一个:等所有衣服异步洗完之后,执行提示“所有衣服都洗完了”;

第二个:读取指定目录下的文件中的字符长,等待所有异步读完之后,打印出总的字符串的长度

        private void button5_Click(object sender, EventArgs e)
        {
            List<Task> tasks = new List<Task>();
            tasks.Add(Task.Run(() =>
            {
                MessageBox.Show("上衣洗好了");
               
            }));
            tasks.Add(Task.Run(() =>
            {
                MessageBox.Show("裤子洗好了");
            }));
            tasks.Add(Task.Run(() =>
            {
                MessageBox.Show("袜子洗好了");
            }));
            Task.WhenAll(tasks).ContinueWith(t => {
                MessageBox.Show($"衣服都洗好了,可以晾了");
            });
        }
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string[] files = Directory.GetFiles(@"C:\Users\liyumin\Desktop\test");
            Task<int>[] strLengthTasks = new Task<int>[files.Length];
            for (int i = 0; i < files.Length; i++)
            {
                Task<int> t = GetFileStringLength(files[i]);
                strLengthTasks[i] = t;
            }
            //等待所有异步任务执行完成
            int[] length = await Task.WhenAll(strLengthTasks);
            Console.WriteLine($"所有文件的字符串总和为:{length.Sum()}");
        }

        /// <summary>
        /// 异步读取指定文件的字符串长度
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private static async Task<int> GetFileStringLength(string fileName)
        {
            string text = await File.ReadAllTextAsync(fileName);
            return text.Length;
        }
    }
}

 

  • 异步编程需要注意的点:

  1. 接口和抽象方法不能修饰为async,async是提示编译器为了异步方法中的await代码进行分段处理的,而一个异步方法是否修饰了async对于方法的调用者来说没有区别,因此接口方法和抽象方法不能修饰为async。(从反编译的async-await方法的代码看,编译器把异步方法拆分成多部分的状态机代码通过moveNext()方法来执行)

 

  • 异步与yield
  1. yield return 相当于流式返回,不需要等待所有集合项获取到之后再统一返回,而是获取一个返回一个,这对于项目中获取一些大型数据集合时比较适合。

        private IEnumerable<string> GetData()
        {
            yield return "1";
            yield return "3";
            yield return "2";
            yield return "4";
            yield return "5";
            yield return "6";
        }
  1. 在旧版C#中,async不能用来修饰yield,从C#8.0开始,把返回值修饰为IAsyncEnumerable(不带Task),然后遍历使用的时候使用await foreach即可。

调试代码时候,可以发现,集合获取一个,控制台打印一个:

 

 

  • ASP.Net Core 和控制台项目中没有SynchronizationContext ,因此不用管ConfigureWait(falsed)等,不要同步和异步混用。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值