.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)等,不要同步和异步混用。

相关推荐

  1. GoLang核心知识

    2024-07-22 22:34:01       30 阅读
  2. Spring核心知识

    2024-07-22 22:34:01       34 阅读
  3. 深度学习的核心数学知识

    2024-07-22 22:34:01       30 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-22 22:34:01       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-22 22:34:01       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-22 22:34:01       45 阅读
  4. Python语言-面向对象

    2024-07-22 22:34:01       55 阅读

热门阅读

  1. WEB开发-HTTP认证

    2024-07-22 22:34:01       12 阅读
  2. ubuntu PlayOnLinux

    2024-07-22 22:34:01       15 阅读
  3. 设计模式实战:库存管理系统的设计与实现

    2024-07-22 22:34:01       12 阅读
  4. 深入理解Python中的闭包和装饰器

    2024-07-22 22:34:01       15 阅读
  5. C++ STL nth_element 用法

    2024-07-22 22:34:01       12 阅读
  6. 低空经济“芯”挑战

    2024-07-22 22:34:01       16 阅读
  7. Python应用—给暑假熊孩子出算术题

    2024-07-22 22:34:01       16 阅读