当前位置: 首页 > news >正文

.NET进阶篇06-async异步、thread多线程2

知识须要不断积累、总结和沉淀,思考和写做是成长的催化剂web

内容目录

1、线程Thread
一、生命周期
二、后台线程
三、静态方法
1.线程本地存储
2.内存栅栏
四、返回值
2、线程池ThreadPool
一、工做队列
二、工做线程和IO线程
三、和Thread区别
四、定时器

1、线程Thread

.NET中线程操做封装为了Thread类,可让开发者对线程进行直观操做。Thread提供了实例方法用于管理线程的生命周期和静态方法用于控制线程的一些访问存储等一些外在的属性,至关于工做空间环境变量了网络

一、生命周期

线程的生命周期有建立、启动、可能挂起、等待、恢复、异常、而后结束。用Thread类能够容易控制一个线程的全生命周期多线程

Thread类的构造函数重载能够接受ThreadStart无参数和ParameterizedThreadStart有参数的委托,而后调用实例的Start()方法启动线程。Thread的构造函数的带有参数的委托,参数是一个object类型,由于咱们能够传入任何信息app

Thread t1 = new Thread(() => {Console.WriteLine($"新线程  {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
});
t1.Start();
Thread t2 = new Thread((obj) => {Console.WriteLine($"新线程  {Thread.CurrentThread.ManagedThreadId.ToString("00")},参数 {obj.ToString()}");
});
t2.Start("hello kitty");

线程启动后,能够调用线程的Suspend()挂起线程,线程就会处于休眠状态(不继续执行线程内代码),调用Resume()唤醒线程,还有一个不太建议使用的Abort()经过抛出异常的方式来销毁线程,随后线程的状态就会变为AbortRequested框架

经常使用的还有线程的等待,在主线程上启用工做线程后,有时须要等待工做线程的完成后,主线程才继续工做。能够调用实例方法Join(),固然咱们能够传入时间参数来代表我主线程最多等你多久异步

二、后台线程

上一章咱们知道Thread默认建立的是前台线程,前台线程会阻止系统进程的退出,就是启动以后必定要完成任务的后台线程会伴随着进程的退出而退出。经过设置属性IsBackground=true改成后台线程。另外还能够经过设置Priority指定线程的优先级。但这个并不总会如你所想设置了高优先级就必定最早执行。操做系统会优化调度,这也是线程不太好控制的缘由之一函数

三、静态方法

上面介绍的都是Tread的实例方法,Thread还有一些经常使用静态方法。有时线程设置不当,会有些意想不到的的bug性能

1.线程本地存储

AllocateDataSlot和AllocateNamedDataSlot用于给全部线程分配一个数据槽。像下面例子所示,若是不在子线程中给数据槽中放入数据,是获取不到其余线程往里面放的数据。测试

var slot= Thread.AllocateNamedDataSlot("testSlot");
//Thread.FreeNamedDataSlot("testSlot");
Thread.SetData(slot, "hello kitty");
Thread t1 = new Thread(() => {//Thread.SetData(slot, "hello kitty");var obj = Thread.GetData(slot);Console.WriteLine($"子线程:{obj}");//obj没有值
});
t1.Start();var obj2 = Thread.GetData(slot);
Console.WriteLine($"主线程:{obj2}");

在声明数据槽的时候.NET提醒咱们若是要更好的性能,请使用ThreadStaticAttribute标记字段。什么意思?咱们来看下面这个例子

//
// 摘要:
//     在全部线程上分配未命名的数据槽。 为了得到更好的性能,请改用以 System.ThreadStaticAttribute 特性标记的字段。
//
// 返回结果:
//     全部线程上已分配的命名数据槽。
public static LocalDataStoreSlot AllocateDataSlot();

例子中的若是不在静态字段上标记ThreadStatic输出结果就会一致。ThreadStatic标记指示各线程的静态字段值是否惟一

[ThreadStatic]
static string name = string.Empty;
public void Function()
{name = "kitty";Thread t1 = new Thread(() => {Console.WriteLine($"子线程:{name}");//输出空});t1.Start();Console.WriteLine($"主线程:{name}");//输出kitty
}

还有一个ThreadLocal提供线程数据的本地存储,用法和上面同样,在每一个线程中声明数据仅供本身使用

ThreadLocal<string> local = new ThreadLocal<string>() { };
local.Value = "hello kitty";
Thread t = new Thread(() => {Console.WriteLine($"子线程:{local.Value}");
});
t.Start();
Console.WriteLine($"主线程:{local.Value}");

上面的静态方法用于线程的本地存储TLS(Thread Local Storage),Thread.Sleep方法在开发调试时也是常常用的,让线程挂起指定的时间来模拟耗时操做

2.内存栅栏

先说一个常识问题,为何咱们发布版本时候要用Release发布?Release更小更快,作了不少优化,但优化对咱们是透明的(计算机里透明认为是个黑盒子,内部逻辑细节对咱们不开放,和生活中透明意味着彻底掌握了解不欺瞒恰好相反),通常优化不会影响程序的运行,咱们先借用网上的一个例子

bool isStop = false;
Thread t = new Thread(() => {bool isSuccess = false;while (!isStop){isSuccess = !isStop;}
});
t.Start();
Thread.Sleep(1000);
isStop = true;
t.Join();
Console.WriteLine("主线程执行结束");

上面例子若是在debug下能正确执行完直到输出“主程序执行结束”,然而在release下却一直会等待子线程的完成。这里子线程中isStop一直为false。首先这是一个由多线程共享变量引发的问题,因此咱们建议最好的解决办法就是尽可能不共享变量,其次可使用Thread.MemoryBarrier和VolatileRead/Write以及其余锁机制牺牲一点性能来换取数据的安全。(上面例子测试若是在子线程while中进行Console.writeLine操做,奇怪的发现release下也能正常输出了,猜想应该是进行了内存数据的更新)

release优化会将t线程中的isStop变量的值加载到CPU Cache中,而主线程修改了isStop值在内存中,因此子线程拿不到更新后的值,形成数据不一致。那么解决办法就是取值时从内存中获取。Thread.MemoryBarrier()就可让在此方法以前的内存写入都及时的从CPU Cache中更新到内存中,在此以后的内存读取都要从内存中获取,而不是CPU Cache。在例子中的while内增长Thread.MemoryBarrier()就能避免数据不一致问题。VolatileRead/Write是对MemoryBarrier的分开解释,从处理器读取,从处理器写入。

四、返回值

前面声明线程时,能够传递参数,那么想要有返回值该如何去作呢?Thread并无提供返回值的操做,后面.NET给出的对Thead的高级封装给出了解决方案,直接使用便可。那目前咱们使用thread类就要本身实现下带有返回值的线程操做,都是经过委托实现的,这里简单介绍一种,(共享外部变量也是能够,不建议)

private Func<T> ThreadWithReturn<T>(Func<T> func)
{T t = default(T);Thread thread = new Thread(() =>{t = func.Invoke();});thread.Start();return () =>{thread.Join();return t;};
}
//调用
Func<int> func = this.ThreadWithReturn<int>(() =>
{Thread.Sleep(2000);return DateTime.Now.Millisecond;
});
int iResult = func.Invoke();

2、线程池ThreadPool

.NET起初提供Thread线程类,功能很丰富,API也不少,因此使用起来比较困难,何况线程还不都是很像理想中运行,因此从2.0开始提供了ThreadPool线程池静态类,全是静态方法,隐藏了诸多Thread的接口,让线程使用起来更轻松。线程池可用于执行任务、发送工做项、处理异步 I/O、表明其余线程等待以及处理计时器

一、工做队列

经常使用ThreadPool线程池静态方法QueueUserWorkItem用于将方法排入线程池队列中执行,若是线程池中有闲置线程就会执行,QueueUserWorkItem方法的参数能够指定一个回调函数委托而且传入参数,像下面这样

ThreadPool.QueueUserWorkItem((obj) => {Console.WriteLine($"线程池中线程  {Thread.CurrentThread.ManagedThreadId.ToString("00")} ,传入 {obj.ToString()}");},"hello kitty");
二、工做线程和IO线程

通常异步任务的执行,不涉及到网络文件等IO操做的,计算密集型,开发者来调用。而IO线程通常用在文件网络上,是CLR调用的,开发者无需管。工做线程发起文件访问调用,由驱动器完成后通知IO线程,IO线程则执行异步任务的回调函数

获取和设置最小最大的工做线程和IO线程

ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
ThreadPool.SetMaxThreads(16, 16);
ThreadPool.SetMinThreads(8, 8);
三、和Thread区别

若是计算机只有8个核,同时能够有8个任务运行。如今咱们有10个任务须要运行,用Thread就须要建立10个线程,用ThreadPool可能只须要利用8个线程就行,节约了空间和时间。线程池中的线程默认先启动最小线程数量的线程,而后根据须要增减数量。线程池使用起来简单,但也有一些限制,线程池中的线程都是后台线程,不能设置优先级,经常使用于耗时较短的任务。线程池中线程也能够阻塞等待,利用ManualResetEvent去通知,但通常不会使用。

四、定时器

.NET中有不少能够实现定时器的功能,在ThreadPool中,咱们能够利用RegisterWaitForSingleObject来注册一个指定时间的委托等待。像下面这样,将每隔一秒就输出消息

ThreadPool.RegisterWaitForSingleObject(new AutoResetEvent(true), new WaitOrTimerCallback((obj, b) =>
{Console.WriteLine($"obj={obj},tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
}),"hello kitty",1000,false);

咱们日常见过比较多的仍是timer类,timer类在.net内是好几个地方都有的,在System.Threading、
System.Timer、System.Windows.Form、System.Web.UI等里面都有Timer,后面都是在第一个System.Threading里的Timer扩展

System.Threading.Timer timer = new System.Threading.Timer((obj) =>
{Console.WriteLine($"obj={obj},tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
},"hello kitty",1000,1000);

timer的底层有一个TimerQueue,利用ThreadPool.UnsafeQueueUserWorkItem来完成定时功能,和上面咱们使用的ThreadPool定时器有一点区别

实际开发中,简单定时timer就够用,但通常业务场景比较复杂,须要定制个性化的定时器,好比每个月几号执行,每个月第几个星期几,几点执行,工做日执行等。所以咱们使用Quarz.NET定时框架,后面框架整合时会用到,用起来也是很简单的

先就啰嗦这两点吧,下一篇应该是Task、Parallel以及Async/Await,而后总结介绍下C#的线程模式、线程同步锁机制、异常处理,线程取消,线程安全集合和常见的线程问题

天长水阔,见字如面,随缘更新,拜了个拜~

相关文章:

.NET进阶篇06-async异步、thread多线程2

知识须要不断积累、总结和沉淀&#xff0c;思考和写做是成长的催化剂web 内容目录 1、线程Thread 一、生命周期 二、后台线程 三、静态方法 1.线程本地存储 2.内存栅栏 四、返回值 2、线程池ThreadPool 一、工做队列 二、工做线程和IO线程 三、和Thread区别 四、定时器 1、线…...

java 方法

方法&#xff1a; 什么是方法&#xff0c;有什么用&#xff1f; 方法&#xff08;英语单词&#xff1a;method&#xff09;是可以完成某个特定功能的并且可以被重复利用的代码片段。 在 C 语言中&#xff0c;方法被称为“函数”。在 java 中不叫函数&#xff0c;叫做方法。 方法…...

HarmonyOS 组件通用属性之通用事件 文档参数讲解(点击事件)

我们组件中 会有很多通用的信息和方法 那么 首先 我们看通用事件 通用事件中 最常用的就是我们的点击事件 比如说 我们之前常写的 组件.onClick(()>{//事件逻辑 })但是 我们之前 都没有用它接参数 我们可以这样 Button("跳转").onClick((ewat: ClickEvent)>…...

毕业设计之开题报告

终于轮到我来写开题报告了&#xff0c;呃呃呃呃呃&#xff0c;目前有点难产了。想做的东西是关于区块链的后端设计实现&#xff0c;但是因为是完全原创之前没有类似的项目能去参考&#xff0c;所以其实有点慌的。 框架梳理 这是我们开题报告的要求&#xff1a; 包括题目研究的…...

【数据结构】详细剖析线性表

顺序表与链表的比较 导言一、线性表二、线性表的存储结构三、顺序表和链表的相同点四、顺序表与链表之间的差异五、存储结构的选择六、静态顺序表的基本操作七、无头结点单链表的基本操作结语 导言 大家好&#xff0c;很高兴又和大家见面啦&#xff01;&#xff01;&#xff0…...

通过数字证书对PDF电子文件进行数字签名/盖章

以下代码详细说明如何使用数字证书对PDF电子文件进行数字签名/盖章。PDF文件签署主要传递PDF文件&#xff0c;数字证书信息&#xff0c;签章图片3个信息。代码中需要的文件、数字证书、签章图片可访问开放签电子签章开源系统详细了解系统的实现与效果。也可通过gitee开源社区下…...

2007~2016 年税调经纬度及其所处的省市区县乡镇数据

之前给大家分享过一份税调企业经纬度及其所处的省市区县数据: 2007~2016 年税调企业地理信息数据(含经纬度及其所处的省市区县):https://rstata.duanshu.com/#/course/76d38022cd004b09b2aa09647936beb0 最近有培训班的小伙伴提出是否能根据税调企业经纬度来判断其所属的乡…...

SLAM学习入门--编程语言

文章目录 编程语言一、C/C++C 与 C++ 的区别(面向对象的特点)C++ 与 Python的区别判断struct的字节数static 作用Const 作用extern "C"的作用多态如何实现多态?虚函数虚函数怎么实现的?析构函数虚析构函数的作用virtual函数能不能用在构造函数中&#...

Go语言程序设计-第6章--方法

Go语言程序设计-第6章–方法 对象就是简单的一个值或者变量&#xff0c;并且拥有其方法&#xff0c;而方法是某种特定类型的函数。 6.1 方法的声明 方法的声明和普通函数的声明类似&#xff0c;只是在函数名字前面多了一个参数。这个参数把这个方法绑定到这个参数对应的类型…...

AI按理说应该最擅长理工,为啥先冲击文艺行业?

介绍 本人数据AI工程师&#xff0c;我的观点对全行业都有冲击&#xff0c;当AI大模型持续进化之时&#xff0c;没有一家公司能独善其身。 本文从产业架构上、论文体量、基础Pass能力、通用大模型、AI开源社区、业务属性大模型、内容消费工具、创作工具赛道、企业服务这些板块…...

蓝牙物联网移动硬件数据传输系统解决方案

随着传感器技术、网络技术和数据传输技术的不断发展&#xff0c;人们对智能设备的需求日渐增强,利用传感器技术可以对周围环境进行准确和全面的感知&#xff0c;获取到实时信息&#xff0c;从而在网络中进行传输和共享&#xff0c;再通过服务器对各种数据进行保存、分析和挖掘等…...

Linux下Web服务器工作模型及Nginx工作原理详解

文章目录 1. 工作模型概述1.1 阻塞、非阻塞、同步、异步浅析1.2 Web服务器处理并发请求的方式 2. Linux下的I/O模型2.1 常用I/O模型2.2 对比以上模型 3. Nginx工作原理3.1 Nginx基本架构3.2 Nginx代码结构3.3 Nginx工作流程3.4 Nginx缓存机制3.5 Nginx缓存工具&#xff1a;Memc…...

AJAX: 整理2:学习原生的AJAX,这边借助express框架

1. npm install express 终端直接安装 2. 测试案例&#xff1a;Hello World&#xff01; 新建一个express.js的文件&#xff0c;写入下方的内容 // 1. 引入express const express require(express)// 2. 创建服务器 const app express()// 3.创建路由规则 // request 是对请…...

二、计算机软件及其使用-文字处理软件 Word 2016

Word 2016 的功能&#xff1b;Word 2016 的启动方法和工作窗口 Word 2016 的功能 编辑功能、排版功能、表格处理功能、图形与公式处理功能、文档管理功能 Word 2016 的启动方法 桌面有就单击、任务栏有就单击、开始菜单中单击 Word 2016 的工作窗口 标题栏、功能区、工作区、状…...

Linux LVM逻辑卷

一、LVM的定义 LVM 是 Logical Volume Manager 的简称&#xff0c;译为中文就是逻辑卷管理。它是 Linux 下对硬盘分区的一种管理机制。LVM 适合于管理大存储设备&#xff0c;并允许用户动态调整文件系统的大小。此外&#xff0c;LVM 的快照功能可以帮助我们快速备份数据。LVM 为…...

Hive生产调优介绍

1.Fetch抓取 Fetch抓取是指&#xff0c;Hive中对某些情况的查询可以不必使用MapReduce计算。例如&#xff1a;SELECT * FROM employees;在这种情况下&#xff0c;Hive可以简单地读取employee对应的存储目录下的文件&#xff0c;然后输出查询结果到控制台。 在hive-default.xml…...

如何理解鼠标点击事件在程序中的处理

在计算机用户界面中&#xff0c;鼠标点击是一个常见的交互动作。那么&#xff0c;当你按下鼠标时&#xff0c;程序是如何知道这个点击是否针对它自己的按钮的呢&#xff1f;本文将探讨鼠标点击事件在操作系统和应用程序之间的传递过程。 鼠标点击事件的捕获 当你按下鼠标按钮…...

基于JWT的用户token验证

1. 基于session的用户验证 2. 基于token的用户身份验证 3. jwt jwt代码实现方式 1. 导包 <dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.18.2</version> </dependency> 2. 在登录…...

通过 conda 安装 的 detectron2

从 detectron2官网 发现预编译的版本最高支持 pytorch1.10、cuda11.3。&#xff08;2023-12-26&#xff09; 1、安装 conda 环境。 conda create --name detectron2 python3.8 2、安装 pytorch1.10 和 cuda11.3。 pip3 install torch1.10.0cu113 torchvision0.11.1cu113 torc…...

嵌入式开发——SPI OLED屏幕案例

学习目标 掌握移植方法掌握调试方式学习内容 需求 官方测试示例 选择对应的平台 测试示例中,找到芯片对应平台,我们选择的是STM32F407 修改例程 已知错误修改:...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...