C# .Net学习笔记—— 异步和多线程(Task)

news2025/5/26 3:26:57

一、概念

Task是DotNet3.0之后所推出的一种新的使用多线程的方式,它是基于ThreadPool线程进行封装的。

二、使用多线程的时机

任务能够并发运行的时候,提升速度;优化体验

三、基本使用方法

        private void button5_Click(object sender, EventArgs e)
        {
            Log.Info($"Task Start {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
            Task.Run(() => this.DoSomethingLong("BtnTask_Click1"));
            Task.Run(() => this.DoSomethingLong("BtnTask_Click2"));
            Log.Info($"Task End {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
        }

        private void DoSomethingLong(string name)
        {
            Log.Info($"DoSomethingLong Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {name} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
            long result = 0;
            for (int i = 0; i < 10000000; i++)
            {
                result += i;
            }
            Thread.Sleep(2000);
            Log.Info($"DoSomethingLong End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {name} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
        }

方法一:

Task.Run(() => this.DoSomethingLong("BtnTask_Click1"));

方法二(这种方式是在DotNet4.0之后出现的):

TaskFactory taskFactory = Task.Factory;
taskFactory.StartNew(() => this.DoSomethingLong("btnTask_Click3"));

方法三:

new Task(() => this.DoSomethingLong("btnTask_Click4")).Start();

四、小案例

题目:现在我有一个项目,产品经理负责提需求,设计产品(主线程)。五位同学分别执行策划、前端、后端、数据库、服务器(子线程)。等所有工作完成后(所有子线程运行结束),再通知甲方过来验收

       //什么时候用多线程?
        //任务能并发进行;
        private void button7_Click(object sender, EventArgs e)
        {
            List<Task> taskList = new List<Task>();

            Log.Info($"项目经理启动一个项目...{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
            Log.Info($"前置的准备工作...{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
            Log.Info($"开始变成...{Thread.CurrentThread.ManagedThreadId.ToString("00")}");

            taskList.Add(Task.Run(() => this.Coding("周同学", "负责策划")));
            taskList.Add(Task.Run(() => this.Coding("黄同学", "负责前端")));
            taskList.Add(Task.Run(() => this.Coding("林同学", "负责后端")));
            taskList.Add(Task.Run(() => this.Coding("陈同学", "负责数据库")));
            taskList.Add(Task.Run(() => this.Coding("陈同学", "负责服务器")));

            //会阻塞当前线程,等着某个任务完成后才进行下一行,卡界面
            Task.WaitAny(taskList.ToArray());
            Log.Info($"已经有一个人完成了...{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
            //多线程加快速度,但是全部任务完成后才能执行的操作
            Task.WaitAll(taskList.ToArray()); //会阻塞当前线程,等着全部任务完成后,才会进入下一行,卡界面
            Log.Info("告诉甲方验收,上线使用");


            //Task.WhenAny(taskList.ToArray()).ContinueWith(t =>
            //{
            //    Log.Info($"哈哈哈哈我第一个做完了...{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
            //});
            //Task.WhenAll(taskList.ToArray()).ContinueWith(t =>
            //{
            //    Log.Info($"部署环境,联调测试...{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
            //});
        }


        private void Coding(string name, string task)
        {
            Log.Info($"Coding {name} Start {task} 线程号:{Thread.CurrentThread.ManagedThreadId.ToString("00")}  时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
            long result = 0;
            for (int i = 0; i < 1000000000; i++)
            {
                result += i;
            }
            Log.Info($"Coding {name} End {task} 线程号:{Thread.CurrentThread.ManagedThreadId.ToString("00")}  时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
        }

知识点:

1、这里Task.WaitAll()会阻塞当前线程,等着全部任务完成后才会继续下一行。这种方式会卡界面

2、Task.WaitAll()第二个参数也可以带参,限时等待

3、Task.WaitAny(taskList.ToArray()) ; 会阻塞当前线程,等着某个任务完成后才进行下一行,卡界面

 WaitAll的使用时机(以某宝为例):

一个业务查询操作有多个数据源,首页-多线程并发-拿到全部数据后才能返回

WaitAny的使用时机(以某宝为例):

一个商品搜索有多个数据源,商品搜索-多个数据源-多线程并发-只需要一个结果即可

WaitAll和WaitAny都是阻塞方法,需要完成后再继续,这会导致卡界面 

 WhenAll和WhenAny是非阻塞方法,不会导致卡界面

 五、控制最大线程的并发数量

       private void button8_Click(object sender, EventArgs e)
        {
            Log.Info($"Coding Start 线程号:{Thread.CurrentThread.ManagedThreadId.ToString("00")}  时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");

            ThreadPool.SetMinThreads(8, 8);
            for (int i = 0; i < 100; i++)
            {
                Task.Run(() => 
                {
                    Log.Info($"{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    Thread.Sleep(2000);
                });
            }
        }

这里通过SetMaxThreads去控制最大的线程并发数量,这种方法并不好,因为ThreadPool是全局的。下面写一种比较合适的方法(用10个线程完成1万个任务):

            {
                //用10个线程完成1万个任务
                List<int> list = new List<int>();
                for (int i = 0; i < 10000; i++)
                {
                    list.Add(i);
                }
                Action<int> action = i =>
                {
                    Log.Info($"{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    Thread.Sleep(new Random().Next(100, 300));
                };
                List<Task> taskList = new List<Task>();
                //这里先启动任务
                foreach (var i in list)
                {
                    int k = i;
                    taskList.Add(Task.Run(() => action.Invoke(k)));
                    //判断个数
                    if (taskList.Count > 10)
                    {
                        //这里开始等着
                        Task.WaitAny(taskList.ToArray());
                        //等到某个线程完成后,把还没完成的留着,已完成的清掉。
                        //这样就可以完成对数量的控制
                        taskList = taskList.Where(t => t.Status != TaskStatus.RanToCompletion).ToList();
                    }
                }
                Task.WhenAll(taskList.ToArray());
            }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1355688.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spark内核解析-数据存储5(六)

1、Spark的数据存储 Spark计算速度远胜于Hadoop的原因之一就在于中间结果是缓存在内存而不是直接写入到disk&#xff0c;本文尝试分析Spark中存储子系统的构成&#xff0c;并以数据写入和数据读取为例&#xff0c;讲述清楚存储子系统中各部件的交互关系。 1.1存储子系统概览 …

RT-Thread 14. GD32F330RBT6 Keil4移植RT-Thread

1.增加rt-thread-v4.1.0源码 rt-thread-v4.1.0\bsp\gd32350r-eval复制重命名为gd32f330_v1 2.文件组织结构 Usr&#xff1a;存放App任务应用&#xff0c;属于应用层&#xff0c;完全脱离硬件 CMSIS&#xff1a;硬件层&#xff0c;启动文件、系统文件 Driver&#xff1a;硬件外…

Spring实现IoC:依赖注入/构造注入

● 控制反转&#xff0c;反转的是什么&#xff1f; ○ 将对象的创建权利交出去&#xff0c;交给第三方容器负责。 ○ 将对象和对象之间关系的维护权交出去&#xff0c;交给第三方容器负责。 ● 控制反转这种思想如何实现呢&#xff1f; ○ DI&#xff08;Dependency Injection&…

通过IP地址如何进行网络安全防护

IP地址在网络安全防护中起着至关重要的作用&#xff0c;可以用于监控、过滤和控制网络流量&#xff0c;识别潜在威胁并加强网络安全。以下是通过IP地址进行网络安全防护的一些建议&#xff1a; 1. 建立IP地址白名单和黑名单&#xff1a; 白名单&#xff1a;确保只有授权的IP地…

UMLChina书籍大全(2024)软件方法人月神话人件企业应用架构模式UML参考手册彩色UML建模领域驱动设计对象设计……

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 以下列出有UMLChina标记的书。 首先是写了十几年还没有写完的软件方法 其他的是译作&#xff1a; 人月神话 2002年&#xff0c;UMLChina和清华大学出版社合作&#xff0c;翻译了《人…

老生常谈:Web 与低代码开发

Web技术和低代码平台是当前技术领域中的两个热门话题。它们在应用开发领域中扮演着重要的角色&#xff0c;不断被提及和讨论。本文将讨论为什么“Web与低代码”这个话题成为了“老生常谈”&#xff0c;探讨其背后的原因以及这两个概念的关系。 在当今技术飞速发展的时代&#x…

imgaug库指南(二):从入门到精通的【图像增强】之旅

文章目录 引言前期回顾代码示例小结结尾 引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应…

静态S5在项目管理中的应用与案例分享

静态S5作为一种强大的数据分析工具&#xff0c;不仅在数据处理和可视化方面表现出色&#xff0c;还在项目管理中发挥着重要作用。本篇将通过实际案例分享&#xff0c;探讨静态S5在项目管理中的应用与优势。 一、静态S5在项目管理中的应用 项目进度管理&#xff1a;静态S5通过…

每日一题——LeetCode1046.最后一块石头的重量

方法一 暴力排序 保证数组从小到大排序&#xff0c;所以最后两个就是最大的石头&#xff0c;每次取最后两个元素进行比较&#xff0c;一样重就直接下一次循环&#xff0c;不一样重就把两个石头重量差push进数组&#xff0c;把数组再次排序 循序嵌套sort排序时间复杂度较高&am…

基于SSM的汽车出租管理系统

目录 前言 开发环境以及工具 项目功能介绍 管理系统 详细设计 登录页面 客户信息管理 汽车信息管理 系统日志记录 汽车租赁功能 出租单入库检查功能 源码获取 前言 本项目是一个基于IDEA和Java语言开发基于SSM的汽车出租管理系统。应用包含管理系统&#xff1b; 汽…

LeetCode(33) 搜索旋转排序数组

整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], ..…

AD自动求导算法

Jacobian matrix 雅可比矩阵 在后面的前向反向积累会用到。AD需要用到中间变量的导数&#xff0c;所以Jacobian matrix就是来计算这些的。 Hessian矩阵 在牛顿法的优化中有应用。 牛顿法 Newton-type methods 自动求导 Automatic Differentiation, AD 数值微分 import n…

构建企业级AI中台,实现业务场景价值闭环

从数据资产到模型资产&#xff0c;大模型的发展&#xff0c;正在加速企业构建AI中台&#xff0c;旨在让更多 AI 的能力能够被构建出来、能够被管理起来、能够面向业务开放起来&#xff0c;打通从数据到模型到最后决策的全链路。 本文将从为什么建AI中台、如何建AI中台、企业AI…

盲盒、一番赏小程序搭建,打开线上盲盒市场

近几年&#xff0c;我国潮玩市场发展非常迅速&#xff0c;在互联网的影响下&#xff0c;盲盒更是迅速走红网络&#xff0c;深受年轻人的喜欢&#xff0c;各大社交平台上关于盲盒的讨论度也是层出不穷。 一番赏与盲盒的机制都是差不多的&#xff0c;盲盒是在包装一样的盒子中放…

ubuntu系统如何安装man命令的中文文档

ubuntu系统如何安装man命令的中文文档 背景 在Linux系统上需要使用一些命令的时候&#xff0c;往往会通过man命令去查询命令的使用方法和参数的说明&#xff0c;但是这些文档说明都是英文的&#xff0c;怎么样才能变成中文的文档&#xff0c;看上去更加清晰呢&#xff1f; 解…

到底谁还在用企业公示系统,聪明的人已经...

随着互联网和数字经济的发展&#xff0c;企业背调变得越来越重要了。毕竟现在企业数量不断增加&#xff0c;据调查数据显示&#xff1a;截止到23年8月11日全国市场总量已经达到3.4亿户&#xff0c;今年新增2049万户。 其中&#xff0c;企业总量9922万户&#xff0c;今年新增621…

线性代数-第五课,第六课,第七课,第八课

第五课 判断某向量是否可由某向量组线性表示 把向量组组成一个行列式&#xff0c;计算行列式的秩 把所有向量放在一起构成一个行列式&#xff0c;计算行列式的秩 如果两个行列式的秩相等&#xff0c;表示可以线性表示&#xff0c;写答案的格式如下 线性表示&#xff1a;bk…

深入浅出XTTS:Oracle数据库迁移升级利器

演讲大纲&#xff1a; 1. 什么是XTTS 2. 适用场景 3. XTTS的基本操作步骤 4. XTTS案例分享 今天主要跟大家分享一下XTTS,在网上曾看过相关讨论,但发现按网上讲的那些去实际操作的话,还是会遇到一些坑,并不能实际落下来,所以今天想跟大家分享一些实战干货. 一、什么是XTTS …

Linux第5步_测试虚拟机网络连接

安装好VMwareTools后&#xff0c;就可以测试虚拟机网络连接了&#xff0c;目的是实现虚拟机上网。 1、打开“控制面板”&#xff0c;得到下图&#xff1a; 2、双击“网络和 Internet” &#xff0c;得到下图&#xff1a; 3、双击“网络和共享中心” 4、点击“更改适配器设置”…

海康威视摄像头+服务器+录像机配置校园围墙安全侦测区域入侵侦测+越界侦测.docx

一、适用场景 1、校园内&#xff0c;防止课外时间翻越围墙到校外、从校外翻越围墙到校内&#xff1b; 2、通过服务器摄像头的侦测功能及时抓图保存&#xff0c;为不安全因素提供数字化依据&#xff1b; 3、网络录像机保存监控视频&#xff0c;服务器保存抓拍到的入侵与越界&am…