首页 > 其他分享 >多线程、任务、异步的区别

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

时间:2024-09-03 22:52:15浏览次数:3  
标签:异步 Task Thread 区别 执行 threadScheduler 任务 线程 多线程

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);
	}
}


//测试
ThreadPoolScheduler threadScheduler = new ThreadPoolScheduler(2);
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

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

回调

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

异步

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

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

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

标签:异步,Task,Thread,区别,执行,threadScheduler,任务,线程,多线程
From: https://www.cnblogs.com/ggtc/p/18392358

相关文章

  • malloc/free 和 new/delete的区别
    malloc/free和new/delete是C++中两种不同的动态内存管理方法,它们有一些关键的区别:1.内存分配和释放机制malloc和free:函数:malloc是一个C标准库函数,用于从堆中分配指定大小的原始内存块。它返回一个void*指针,指向分配的内存块的起始位置。free用于释放由......
  • 流式dma和一致性dma的区别
    流式DMA(StreamingDMA)和一致性DMA(ConsistentDMA)是两种不同的内存映射模式,用于DMA(直接内存访问)操作。它们的主要区别在于缓存一致性、性能和使用场景。以下是这两者的详细区别:1.流式DMA(StreamingDMA)缓存一致性:流式DMA不保证缓存的一致性。在进行DMA操作前,需要显式......
  • 【多线程】 - 实现方法以及自定义线程池
    概念进程进程是程序的基本执行实体线程线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。多个线程组成了多线程多线程应用场景软件中的耗时操作拷贝、迁移大文件加载大量的资源文件想让多个事情同时运行就需要多线程并发和并行并发在同一时刻......
  • 二、并发编程与多线程-2.1、J.U.C和锁(中篇)
    2.1、J.U.C和锁(中篇)2.1.4、什么是CAS?答:CAS是Java中Unsafe类里面的方法,全称是CompareAndSwap,是比较并交换的意思。作用就是保证在多线程环境下,对于修改共享变量操作的原子性。扩展:CAS保证修改共享变量操作原子性的实现逻辑:CAS方法里有三个参数,依次分别是共享变量的内......
  • Python教程(十七):协程、 asyncio与 aiohttp【异步IO】
    文章目录专栏列表1.异步IO的基本概念1.1同步与异步1.2协程1.3asyncio1.4aiohttp2.携程2.1定义协程2.2运行协程3.asyncio3.1事件循环解释3.2获取文件示例3.2并发获取文件示例4.aiohttp:异步HTTP客户端/服务器4.1安装aiohttp4.2异步HTTP请求4.3异......
  • EasyCVR(V3.6.0)播放鉴权与播放限制时长的区别介绍
    有用户部署EasyCVR视频汇聚平台的新版本后(V3.6.0),发现新增了播放鉴权的配置项,于是咨询我们这个功能和之前的播放限制时长功能有何区别。今天我们就来解释下。其实这两个功能针对性不一样,播放鉴权是针对web页面,播放限制时长则是针对视频流。例如,将播放限制时长设置为2分钟,则代表该通......
  • 智慧安防EasyCVR新版本(V3.6.0)播放鉴权与播放限制时长的区别介绍
    随着科技的飞速发展,视频技术已成为现代社会不可或缺的一部分,广泛应用于安防监控、娱乐传播、在线教育、电商直播等多个领域。EasyCVR视频汇聚平台作为视频技术的佼佼者,不断推陈出新,通过功能更新迭代,为用户提供更加高效、智能、稳定的视频解决方案。有用户部署EasyCVR视频汇聚平......
  • flask多线程下数据库操作(简单示例)
    前言背景:开了两个线程操作数据库插入但是获取不到db的信息,自己摸索的方法不一定是最佳的,有更好的可以评论或私信,感谢大佬话不多说,直接上代码 #模型里面的多线程新增操作@staticmethoddefadd_users_by_thread(username,password,session):user=U......
  • 为什么多线程会带来性能问题?
    为什么多线程会带来性能问题?什么是性能问题在上一篇中,我们已经学习了多线程带来的线程安全问题,但对于多线程而言,它不仅可能会带来线程安全问题,还有可能会带来性能问题,也许你会奇怪,我们使用多线程的最大目的不就是为了提高性能吗?让多个线程同时工作,加快程序运行速度,为什么反而会带来......
  • 业务部门提出我们已经有报表了为什么还要上BI? | BI与报表区别和联系?
    目录0业务质疑 1认知提升 (1)什么是BI(2)BI与大数据有什么关系?(3)BI与信息化、数字化之间的有什么关系? (4)BI与报表之间的区别2企业数据应用现状及BI价值(1)企业数据应用现状(2)BI价值体现 3小结0业务质疑    在数字化建设过程中,IT部门在进行BI项目推进的时......