多线程、任务、异步的区别

news/2024/9/19 2:07:56/文章来源:https://www.cnblogs.com/ggtc/p/18392358

Task和Thread的区别

这是一个高频,深刻的问题,无论去哪都逃不过被询问这个问题。Task是基于Thread的,这是众所周知的。但是Task和Thread的联系如此简单和纯粹确实我没想到的。甚至只需要几十行代码就能呈现其原理。一个简单的模拟实例说明Task及其调度问题,这真是一篇好文章。

任务体系由两个类组成,Task,以及TaskScheduler

Task储存需要到多线程去执行的委托方法,尽管经过层层封装,内部最终还是调用这个委托。但是任务的执行方法不向程序员开放,而是交给了TaskScheduler,暴露给程序员的只有把任务交给任务调度器这个方法。任务说白了是围绕委托这个中心构建的。至于委托在哪个线程上执行,职责不在此,交给了任务调度器。

TaskScheduler用于决定将Task放到哪个线程上执行,最简单的是new Thread将Task及其内部的委托放进新线程去执行。复杂一点的就是调用线程池的排队方法,将Task放到线程池要访问的待执行Task队列中,让队列不断弹出Task,然后放到某个线程中去执行。

实现两个TaskScheduler

我举两个任务调度器来说明这有多简单。一个调度器用于对每个任务创建一个线程执行,另一个调度器用于创建一个线程池,并用线程池的线程去取任务执行。

  • 总是使用新线程执行任务
//使用新线程执行任务
public class ThreadScheduler:TaskScheduler
{protected override void QueueTask(Task task){//没想到就是直接把Task放到Thread中去执行了new Thread(()=>TryExecuteTask(task)).Start();}
}//测试
ThreadScheduler threadScheduler = new ThreadScheduler();
Task.Factory.StartNew(() => Console.WriteLine($"Task1 is excuted in thread {Thread.CurrentThread.ManagedThreadId}"), default, TaskCreationOptions.None, threadScheduler);
Task.Factory.StartNew(() => Console.WriteLine($"Task2 is excuted in thread {Thread.CurrentThread.ManagedThreadId}"), default, TaskCreationOptions.None, threadScheduler);
Task.Factory.StartNew(() => Console.WriteLine($"Task3 is excuted in thread {Thread.CurrentThread.ManagedThreadId}"), default, TaskCreationOptions.None, threadScheduler);
Task.Factory.StartNew(() => Console.WriteLine($"Task4 is excuted in thread {Thread.CurrentThread.ManagedThreadId}"), default, TaskCreationOptions.None, threadScheduler);

image

  • 创建并使用线程池执行任务
//使用线程池执行任务
public class ThreadPoolScheduler:TaskScheduler
{private BlockingCollection<Task> tasks=new();private Thread[] threads;//创建一个线程池,让线程不断去队列中取出任务执行public ThreadPoolScheduler(int threadNum){threads=new Thread[threadNum];for(int i=0;i<threadNum;i++){threads[i]=new Thread(InvokeNext);threads[i].Start();}void InvokeNext(){while(true){var task=tasks.Take();if(task!=null){TryExecuteTask(task);}}}}//新任务入队protected override void QueueTask(Task task){tasks.Add(task);}
}

image

从这两种调度器可以看出,开始一个任务这个动作是唯一明确的只有一点,就是把任务交给调度器,而不是立即执行任务。至于任务有没有立即被放到线程中执行,这却决于任务调度器的实现。比如在第一种调度器中,任务被立即执行;在第二种调度器中,任务可能会等待,直到有空闲线程把它从队列中取出来。

回调

任务和多线程还有一个区别是拥有回调ContinueWith。这样就不需要使用阻塞或线程同步去解决这种很常见的,在一件事完成后再做另一件事的问题。大内老A提出的方式是,在任务内部,在执行委托的那个函数中,在前一个委托执行完成后,开启一个新任务,执行下一个委托。
由于这个触发节点在前一个线程即将结束时,所以能实现回调。
由于回调和开始任务这两个方法有相同返回类型Task,所以又实现了链式调用。

异步

异步的解释是以同步的方式进行异步编程。这是对任务的进一步改进。这玩意只能通过语法糖去实现,达到的效果是将任务的回调执行模型变换为了直观上看起来的顺序执行模型。在多线程同步这个问题上,可以得出这样一条演变链条。

Thread Task async/await
锁,信号量等线程同步 回调 同步的方式编程

异步和多线程有什么区别?主要在于线程同步方式的区别吧。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UART

UART协议帧在 UART中,传输模式为数据包形式。数据包由起始位、数据帧、奇偶校验位和停止位组成。起始位当不传输数据时, UART 数据传输线通常保持高电压电平。若要开始数据传输,发送UART 会将传输线从高电平拉到低电平并保持1 个时钟周期。当接收 UART 检测到高到低电压跃迁…

电路分析 ---- 加法器

1 同相加法器分析过程虚短:\(u_{+}=u_{-}=\cfrac{R_{G}}{R_{G}+R_{F}}u_{O}\) \(i_{1}=\cfrac{u_{I1}-u_{+}}{R_{1}}\);\(i_{2}=\cfrac{u_{I2}-u_{+}}{R_{2}}\);\(i_{3}=\cfrac{u_{I3}-u_{+}}{R_{3}}\);且有\(i_{1}+i_{2}+i_{3}=0\). 所以得到\(\cfrac{u_{I1}}{R_{1}}+\cfr…

docker 配置elasticSearch

1、拉取elasticSearch容器 docker pull docker.elastic.co/elasticsearch/elasticsearch:8.9.0 2、运行容器并且与物理机映射端口(9200,物理机器) 9300(容器端口) docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node&quo…

mini-lsm通关笔记Week1Day7

Summary在上一章中,您已经构建了一个具有get/scan/put支持的存储引擎。在本周末,我们将实现SST存储格式的一些简单但重要的优化。欢迎来到Mini-LSM的第1周零食时间! 在本章中,您将:在SST上实现布隆过滤器,并集成到LSM读路径get中。 以SST块格式实现对key存储的压缩。要将…

记一次我的博客园页面突然无法显示markdown数学公式

记一次我的博客园页面突然无法显示markdown数学公式,之前都还好好的,今天突然给我数学公式卡没了......之前都还好好的,今天突然给我数学公式卡没了......具体情况如下但是我编辑的时候预览明明可以摘要里显示也没有问题给官方写了封邮件后得到回复如下 您好,我们这边测试一…

RRAM流片调试心得

RRAM流片调试心得 去年进行了一次RRAM的流片工作,也是人生第一次流片,一些工作细节不便涉及,但是可以谈谈这次流片以及后续测试中碰到的问题,以便后续查阅。 芯片于UMC完成180nm的CMOS前道工艺,共生长5层金属(到V5),随后出Fab,送到所里生长RRAM和M6完成后道工艺,版图…

C#自定义控件—文本显示、文本设值

C#用户控件之文本显示、设定组件 如何绘制一个便捷的文本显示组件、文本设值组件(TextShow,TextSet)?绘制此控件的目的就是方便一键搞定标签显示(可自定义方法显示文本颜色等),方便自定义方法又省略了挨个拖拽的过程纯定义属性 【文本设定】:字体、标签、值、单位;事件…

搜索组件优化 - Command ⌘K

今天心血来潮想在 `blog` 上找一篇文章,用搜素的功能发现搜不出来😂,搜索挂了?然后突然想起来之前由于想着在 `blog` 中可能加一些私有的配置或者尝鲜的功能,所有 `fork` 了一份变成 私有项目了,这样就不符合 `DocSearch` 的 网站必须是公开的这个限制了。前言: DevNow…

项目协同开发 or 拷贝项目

项目协同开发 or 拷贝项目 给另人项目时一般需要给代码 requiremenets.txtpip freeze > requiremenets.txt #requiremenets.txt 生成方式获得别人代码 pip install -r requiremenets.txt # 自动将:requiremenets.txt 对应的版本进行安装无网络问题-解决安装第三方模块…

深入浅出Stream流

Java 8的新特性之一就是流stream,配合同版本出现的 Lambda ,使得操作集合(Collection)提供了极大的便利。 案例引入 在JAVA中,涉及到对数组、Collection等集合类中的元素进行操作的时候,通常会通过循环的方式进行逐个处理,或者使用Stream的方式进行处理。 假设遇到了这么…

决策树之——ID3算法及示例

0 前言本文主要介绍决策树ID3算法,并举出构建示例帮助理解。 读者需要具备的知识:信息熵、条件熵、信息增益。 本文使用数据集为:游玩数据集 1.1节。1 ID3算法简述 ID3(Iterative Dichotomiser 3)算法是一种经典的决策树学习算法,由Ross Quinlan于1986年提出。该算法的主…

AtCoder ABC 369题解

题解前言 本题解部分思路来源于网络,仅供参考 ! A - 369 题目大意 给定 \(A\) , \(B\) 两个整数,求有多少个整数 \(x\) 使得可以通过某种排列使得 \(A\) ,\(B\) ,\(x\) 为等差数列。解题思路 稍加分析即可得到:如果 \(A = B\) 则结果为 \(1\) 。如果 \(A = B\) 但 \((A …