(十八)Threads异步和多线程(Thread、Threadpool、Task)-语言进阶2

news2024/11/17 11:55:01

Threads异步和多线程-语言进阶2

  • 一、Thread
    • 1. 线程启动
    • 2. 线程等待
    • 3.前台线程/后台线程
    • 4.扩展thread封装回调
  • 二、Threadpool
    • 1.线程池
    • 2.线程池使用
    • 3.ManualResetEvent 线程池等待
  • 三、Task
    • 1. Task启动方式
    • 2.waitall 、waitany
      • 1.waitall
      • 2.waitany
      • 3.WaitAll、waitany场景
      • 4. 应用:线程数量控制
      • 5.扩展:获取哪个任务先完成
    • 3. WhenAny、WhenAll
    • 4.ContinueWherAny、ContinueWhenAll
    • 5.Delay() 延迟
  • 四、并行运算Parallel
    • 1. Parallel启动方式
    • 2. Parallel限制线程数量
      • 1.控制并发量

一、Thread

1. 线程启动

thread.Start();

ThreadStart threadStart = () => this.DoSomethingLong("btnThreads_Click")Thread thread = new Thread(threadStart);
thread.Start() ;

2. 线程等待

  1. 当线程启动之后,我们需要线程等待时,可以用
    thread.Join();//一直等待任务完成
    thread.Join(500); //设置最多等待500ms
  2. Sleep方式
while (thread.ThreadState != ThreadState.Stopped)
{
	Thread.Sleep(100);//当前线程 休息100ms
}

3.前台线程/后台线程

  1. thread.IsBackground默认前台线程,启动之后一定会完成任务,阻止进程退出。
  2. thread.IsBackground=true;设置后台线程,随着进程退出
  3. Thread.Priority;//设置线程优先级,其中CPU会优先执行Highest,不代表说Highest最先完成。
    在这里插入图片描述

4.扩展thread封装回调

  1. thread封装回调
//启动子线程计算--完成委托后,该线程去执行后续回调委托
private void ThreadWithCallback(Action act, Action callback)
{
	Thread thread = new Thread(() =>
	{
		act.Invoke();
		callback.Invoke():
	});
	thread.Start():
}
  1. 带返回的异步调用 需要获取返回值
private Func<T ThreadWithReturn<I>(Func<T> func)
{
	T t = default(T);
	Thread thread = new Thread(()=>
	{
		t = func.Invoke();
	});
	thread.Start() ;
	//返回Func<T>
	return ()=>
	{
		while (thread.ThreadState != ThreadState.Stopped)
		{
			Thread.Sleep(200);
		}
	}
	return t;
}

其中while判断处也可以换成 thread.Join();
调用方式
在这里插入图片描述

二、Threadpool

1.线程池

  1. 线程池:线程池提供了一种限制和管理资源(包括执行一个任务)。 每个线程池还维护一些基本统计信息,例如已完成任务的数量。
  2. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  3. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  4. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统 的稳定性,使用线程池可以进行统一的分配,调优和监控。

2.线程池使用

  1. 线程池启用
    ThreadPool.QueueUserWorkItem();//接受一个WaitCallback类型的参数;
    WaitCallback:没返回值的委托;
    在这里插入图片描述
  2. 线程限制:最大线程
ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortlhreads();

GetMaxThreads:检索可以同时处于活动状态的线程池请求的数目。 所有大于此数目的请求将保持排队状态
workerThreads:线程池重辅助线程的最大数目。
completionPortlhreads:线程池中异步I/O线程的最大数目
3. 线程限制:最小线程

ThreadPool.GetMinThreads(out int workerThreads, out int completionPortlhreads();

3.ManualResetEvent 线程池等待

//ManualResetEvent 类 包含了一个bool属性
//false–WaitOne等待–Set–true–WaitOne直接过去
//true–WaitOne直接过去–reset–false–WaitOne等待

ManualResetEvent manualResetEvent = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(t =>
{
	this.DoSomethingLong("btnThreadPool Click");
	manualResetEvent.Set() :
	//manualResetEvent.Reset() 
});
manualResetEvent.WaitOne ();
Console.WriteLine("等着QueueUserWorkItem完成后才执行");

但不建议这么用,因为一般来说,不要阻塞线程池的线程。

三、Task

Task是基于ThreadPool,增加了多个API

1. Task启动方式

  1. Run
Task.Run(()=>this.DoSomethingLong("btnTask_Click1"));
  1. TaskFactory
TaskFactory taskFactory = Task.Factory;
taskFactory.StartNew(() => this.DoSomethingLong("btnTask Click3")):
new Task(0 => this.DoSomethingLong("btnTask Click4")).Start():

2.waitall 、waitany

1.waitall

waitall:阻塞当前线程,等着任务全部完成,才进入下一行,不过会卡界面
当我们在多线程中,需要在所有任务都完成后,给与正确提示,如下例子,当所有开发任务完成,告诉甲方验收

在这里插入图片描述
可以看下这里的运行结果,实际开发任务并没有完成,但却告诉已经完成,不符合需求在这里插入图片描述
这时我们就可以使用waitall阻塞当前线程,等完成后提示。
在这里插入图片描述
也可以传入指定时间,限时等待。

Task.WaitAll(taskList.ToArray()1000);//限时等待

2.waitany

waitany:会阻塞当前线程,等着某个任务完成后,才进入下一行 卡界面

Task.WaitAny(taskList.ToArray());
Task.WaitAny(taskList.ToArray(),1000);

如果想做到 waitAll和waitAny不卡界面,则可以在包一层task,因为其中卡的是运行线程,包一层则意味着又是一个新的线程在执行
在这里插入图片描述

3.WaitAll、waitany场景

  1. WaitAll:一个业务查询操作有多个数据源——首页——多线程并发——拿到全部数据后才能返回
  2. WaitAny:一个商品搜索操作有多个数据源,商品搜索——多个数据源——多线程并发——只需要一个结果即可

4. 应用:线程数量控制

List<int> list = new List<int>();
for (int i = 0;i < 10000; i++){
	list.Add(i);
}

//完成1000个任务,但只需要11个线程
Actlon<int>action = i =>
{
	Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00"));
	Thread.Sleep(new Random(i).Next(100300));
};
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.WhenA11(taskList.ToArray());

5.扩展:获取哪个任务先完成

  1. 使用TaskFactory在任务中追加标识,使用AsyncState获取任务
    在这里插入图片描述
  2. 如果是Task的话 可以做个子类做属性标识

3. WhenAny、WhenAll

上述我们发现WaitAll、waitany一般情况会卡界面,那么接下来我们来解决这个情况
WhenAny、WhenAll:创建在task完成时,异步执行的延续任务,则不会卡界面,如下
在这里插入图片描述
在这里插入图片描述

4.ContinueWherAny、ContinueWhenAll

ContinueWherAny、ContinueWhenAll则是TaskFactory中使用,效果和WhenAny、WhenAll一样
在这里插入图片描述

5.Delay() 延迟

Task.Delay(1000);延迟 不会卡
Thread.Sleep(1000);等待,会卡

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start0():
Task.Delay(2000).ContinueWith(t =>
{
	stopwatch.Stop () ;
	Console.WriteLine(stopwatch.ElapsedMilliseconds);
}

如果想sleep也不卡的话,仍是包一层task开启个新线程

Stopwateh stopwatch = new Stopwatch();
stopwatch.Start();
Task.Run(()=>
{
	Thread.sleep(2000)stopwatch.Stop();
	Console.WriteLine(stopwatch.ElapsedMilliseconds);
}

四、并行运算Parallel

Parallel:并行编程,在Task的基础上做了封装,卡界面,因为主线程参与计算,节约了一个线程

1. Parallel启动方式

  1. Invole
Parallel.Invoke(() => this.Coding("爱书客""Client"),
	()=> this.Coding("风动寂野","Portal"),
	()=> this.Coding("笑看风云","Service"));
  1. For
//启动5个线程
Parallel.For(0,5,i =>Coding("爱书客","Client"+i));
  1. Foreach
Parallel.ForEach(new string[] { "0","1","2","3","4"),i => this.Coding("爱书客","client"+1));

2. Parallel限制线程数量

1.控制并发量

使用ParallelOptions 的MaxDegree0fParallelism 限制线程数量

ParallelOptions parallelOptions = new ParallelOptions();
parallel0ptions.MaxDegree0fParallelism = 3;//限制3个线程
Parallel.For(0,10,parallelOptions,i =>this.Coding("爱书客","Client"+ i));

在这里插入图片描述
从运行结果可以看到任意时刻只有三个线程在运行。

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

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

相关文章

Spring为什么这么火 之 Spring的创建及存储、获取Bean对象

目录 1、创建Spring项目 1.1、创建一个Maven项目 1.2、添加Spring框架支持 1.3、添加启动类 2、存储Bean对象 2.1、创建Bean对象 2.2、将Bean对象注册到Spring容器中 3、获取、使用Bean对象 3.1、得到Spring上下文对象 使用ApplicationContext作为Spring的上下文 【更…

服务器相关命令(docker相关)

一:安装docker 之前安装过旧版本&#xff0c;使用以下命令可以卸载(整个copy过去): yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-selinux \docker-engine-selinux \docker-e…

AOP面向切面编程

AOP 面向切面编程 AOP是什么 AOP 为 Aspect Oriented Programming 的缩写&#xff0c;意为&#xff1a;面向切面编程&#xff0c;通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。 AOP 是 OOP 的延续&#xff0c;是软件开发中的一个热点&#xff0c;是 j…

【Linux】-- 环境变量

目录 环境变量 常见环境变量 HOME 和环境变量相关的命令 通过代码如何获取环境变量 环境变量参数 通过第三方变量environ获取 通过getenv函数来特定访问获取 通过setenv函数来特定访问获取 环境变量 命令&#xff1a;which ls 将命令ls的完整路径写入到标准输出。 #in…

用R语言理解洛必达法则

文章目录5 洛必达法则极限的种类洛必达法则作用于幂函数5 洛必达法则 极限的种类 令NNN为常数&#xff0c;则常规的极限运算大致有以下几种 ∞N∞∞⋇N∞(N̸0)N∔∞∞N−∞−∞N/∞0N/0∞N∞∞(N̸1)∞N∞(N̸0)\begin{matrix} &\infty\pm N\infty\quad&\infty\divi…

MySQL版本由5.7.37更新到5.7.39

一、前景 由于mysql5.7.37存在漏洞&#xff0c;影响系统安全&#xff0c;所以需要将mysql版本升级到5.7的最新版本5.7.39。 二、步骤 1、下载5.7.39的安装包&#xff1a; 下载链接如下&#xff1a; https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.39-1.el…

node基础知识

node基础知识 node在真实项目中的应用 webpack基于node环境 用nodejs的语法合并压缩打包 js放到客户端浏览器中执行 放到服务器端运行&#xff1a;java因为jdk php因为tomcat c#因为有.net framework 项目架构1&#xff1a;中小型项目-基于nodejs构建全栈 项目架构2&#xff1a…

mysql转DM达梦数据库+springboot兼容DM数据库+springboot兼容activity5.22.0

由于现在做的项目中需要针对数据库进行国产化操作&#xff0c;最终完成从mysql到达梦的迁移&#xff0c;记录整合迁移记录如下&#xff1a;安装初始化达梦数据库&#xff08;傻瓜式安装即可&#xff09;安装达梦数据库&#xff08;windows、linux&#xff09;初始化数据库实例关…

代码质量与安全 | 新时代:2023年商业软件开发的五大关键目标

进入2023年&#xff0c;技术趋势仍然聚焦于人工智能、边缘智能和气候变化领域&#xff0c;但供应链增速放缓和日益增长的消费者需求阻碍着创新的步伐。为了在行业中保持竞争力&#xff0c;并实现软件工程预定目标&#xff0c;软件开发领导者需要主动制定预算和时间管理计划&…

Java设计模式-模板模式Template

介绍 模板方法模式&#xff08;Template Method Pattern&#xff09;&#xff0c;又叫模板模式(Template Pattern)&#xff0c;z 在一个抽象类公开定义了执行。它的方法的模板。它的子类可以按需要重写方法实现&#xff0c;但调用将以抽象类中定义的方式进行。简单说&#xff…

中移链合约常用开发介绍 (二)多索引表的使用

一、目的本文详细介绍了开发、部署和测试一个地址簿的智能合约的流程&#xff0c;适用于EOS的初学者了解如何使用智能合约实现本地区块链上数据的持久化和对持久化数据的增删改查。二、智能合约介绍区块链作为一种分布式可信计算平台&#xff0c;去中心化是其最本质的特征。每笔…

17.Isaac教程--机器学习流程

机器学习流程 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录机器学习流程模拟训练PC 和边缘设备上的推理使用 TensorRT 进行推理Torch推理使用 Tensorflow 进行推理示例PyCodelet配套代码Tensorflow 推理小码TensorRT 推理小码SampleAc…

23种设计模式(三)——模板方法模式【组件协作】

文章目录意图什么时候使用模板方法真实世界类比常说的钩子模板方法的实现模板方法模式的优缺点亦称&#xff1a; Template Method 意图 它的主要思想是&#xff0c;定义一个操作的一系列步骤&#xff0c;对于某些暂时确定不下来的步骤&#xff0c;就留给子类去实现好了&#x…

位图与矢量图的区别

相信大家在日常的工作过程中&#xff0c;经常会听到位图和矢量图&#xff0c;那么位图和矢量图的区别是什么呢&#xff1f; 1.定义 ①位图&#xff1a;称为点阵图像或栅格图像&#xff0c;是由称作像素&#xff08;图片元素&#xff09;的单个点组成的。这 些点可以进行不同的排…

测试用例设计方法有哪些?举例说明

众所周知&#xff0c;测试用例是编制的一组测试输入、执行条件及预期结果&#xff0c;专门为的是某个特殊目标&#xff0c;即测试某个程序路径&#xff0c;或是核实是否满足某个特定的需求。一般来讲&#xff0c;常用的测试用例设计方法有五种&#xff0c;分别是&#xff1a;正…

微信小程序中如何实现双向绑定

一、双向绑定 在微信小程序中如何实现双向绑定&#xff1f;在开始之前先介绍下什么是双向绑定&#xff0c;js中定义变量数据后&#xff0c;通过{{}}绑定到模板中&#xff0c;这个过程是单向绑定&#xff0c;即数据的更新只能是js中更新了数据&#xff0c;模板中跟着修改。但是如…

深度学习笔记:神经网络(3)

关于本章之前内容可以参考以下之前文章&#xff1a; 1 https://blog.csdn.net/Raine_Yang/article/details/128473486?spm1001.2014.3001.5501 2 https://blog.csdn.net/Raine_Yang/article/details/128584916?spm1001.2014.3001.5501 神经网络的输出层设计 机器学习问题一般…

2022年12月青少年软件编程(Python) 等级考试试卷(三级)

2022. 12 青少年软件编程&#xff08;Python&#xff09; 等级考试试卷&#xff08;三级&#xff09; 一、 单选题(共 25 题&#xff0c; 共 50 分) 1.列表 L1 中全是整数&#xff0c; 小明想将其中所有奇数都增加 1&#xff0c; 偶数不变&#xff0c; 于是编写了如下图 所示的…

高级树结构之平衡二叉树(ALV树)

文章目录平衡二叉树简介失衡类型&处理办法RR型失衡【左旋调整】调整演示代码实现LL型失衡【右旋调整】调整演示代码实现RL型失衡【先右旋后左旋调整】调整演示代码实现LR型失衡【先右旋后左旋调整】调整演示代码实现插入操作综合代码演示平衡二叉树简介 在数据有序的情况下…

Codeforces Round #842 (Div. 2)

Codeforces Round #843 (Div. 2) 传送门 不想搞的很累&#xff0c;对自己不做要求&#xff0c;有兴趣就做。 A. Greatest Convex #include <bits/stdc.h>using namespace std; const int maxn 1e6 10; vector<int> cnt[maxn]; map<int, int> mp;int mai…