【.NET Core】多线程之线程池(ThreadPool)详解(二)

2024-01-23 05:20

本文主要是介绍【.NET Core】多线程之线程池(ThreadPool)详解(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【.NET Core】多线程之线程池(ThreadPool)详解(二)

在上一篇《【.NET Core】多线程之线程池(ThreadPool)详解(一)》中我们详细讲解了,线程池概念,如何应用及其应用的场景。本文我们将着重讲解线程池的使用。
在这里插入图片描述

一、线程池原理

CLR线程池并不会在CLR初始化时立即建立线程,而是在应用程序要创建线程来运行任务时,线程池才初始化一个线程。线程池初始化时是没有线程的,线程池里的线程的初始化与其他线程一样,但是在完成任务以后,该线程不会自行销毁,而是以挂起的状态返回到线程池。直到应用程序再次向线程池发出请求时,线程池里挂起的线程就会再度激活执行任务。

这样既节省建立线程所造成的性能损耗,也可以让多个任务反复重用同一线程,从而在应用程序生存期内节约大量开销。

通过CLR线程池所建立的线程总是默认为后台线程,优先级数为ThreadPriotity.Normal

CLR线程池分为工作者线程(WorkerThreads)与I/O线程(CompletionPortThreads)两种:

工作者线程是主要用作管理CLR内部对象的运作,通常用于计算密集的任务。

I/O(Input/Output)线程主要用于与外部对象的运作,通常用于计算密集的任务。

二、通过ThreadPool.QueueUserWorkItem()方法创建线程池

const int cycleNum = 15;
static void Main(string[] args)
{// 设置CLR线程池中工作者线程与I/O线程最大数目和最小数目ThreadPool.SetMinThreads(1, 1);ThreadPool.SetMaxThreads(10, 10);for (int i = 1; i <= cycleNum; i++){// 将方法派入队列,成功返回TURE否则异常System.ArgumentNullExceptionThreadPool.QueueUserWorkItem(new WaitCallback(testFun), i.ToString());}Console.WriteLine("主线程执行!");Thread.Sleep(5300);Console.WriteLine("主线程结束!");Console.ReadKey();
}
public static void testFun(object obj)
{Console.WriteLine(string.Format("{0}:第{1}个线 程,{2}当前线程名称", DateTime.Now.ToString(), obj.ToString(),Thread.CurrentThread.ThreadState));Thread.Sleep(5000);
}

从上面示例你会注意到ThreadPool线程没有Join方法。你无法通过任何直接方法确定线程是否已完成执行。一旦你在ThreadPool中排队工作项,主线程就会继续执行。如果要等到线程完成执行,则必须使用同步事件编写代码。

使用线程同步事件

线程同步事件有两种类型:

  1. ManualResetEvent这是一个像我们家中的普通门一样工作事件,你可以使用.Set()方法设置它并使用.Reset()方法重置(关闭)它。它将阻塞调用.WaitOne()的线程,直到它被设置。设置后,事件对象的状态将处于Set状态,直到你使用.Reset()方法手动重置它。
  2. AutoResetEvent-它的作用与ManualResetEvent相同,只是它的作用类似自动门。一旦你设置它,它运行通过调用.WaitOne()等待的线程通过,然后将自身重置回来。
static void Main(string[] args)
{ManualResetEvent myWaitHandle = new ManualResetEvent(false);ThreadPool.QueueUserWorkItem(new WaitCallback(RunThread), myWaitHandle);myWaitHandle.WaitOne();Console.WriteLine("ThreadPool thread has completed the Work and Set myWaitHandle");Console.ReadLine();
}private static void RunThread(object state)
{ManualResetEvent waitHandleFromParent = (ManualResetEvent)state;Console.WriteLine("I am in ThreadPool Thread");Thread.Sleep(5000);Console.WriteLine("ThreadPool thread is going to exit");waitHandleFromParent.Set();
}

二、通过Task创建线程池

2010年引入的任务并行库中的任务类为你提供了上述两个问题的解决方法。许多人将任务与轻量级线程混淆,但任务不能与线程相提并论。任务只是一组要执行的作业。线程执行调度到TaskScheduler的任务。任务不保证并行处理,并根据资源的可用性进行调度。默认情况为任务衍生新线程。与ThreadThreadPool使用Task可以返回执行结果。

任务不是异步运行的,因为我们在主线程中调用task.Wait(),主线程被阻塞直到任务完成。任务非常适合使用async/await进行异步执行。下面将演示Task创建线程过程:

public static void Main(string[] args)
{var task = new Task(RunTask);task.Start();task.Wait();Console.WriteLine("Back to main thread. Task completed execution!");Console.ReadLine();
}private static void RunTask()
{Console.WriteLine("I am in Task");Thread.Sleep(5000);
}

三、IasyncResult异步线程池

.NET Framework允许你异步调用任何方法。定义与你需要调用的方法具有相同签名的委托;公共语言运行库将自动为该委托定义具有适当签名的BeginInvokeEndInvoke方法。

BeginInvoke方法用于启动异步调用。它与你需要异步执行的方法具有相同的参数,只不过还有两个额外的参数。BeginInvoke立即返回,不等待异步调用完成。BeginInvoke返回IasyncResult,可用于监视调用进度。

EndInvoke方法用于检索异步调用结果。调用BeginInvoke后可随时调用EndInvoke方法;如果异步调用未完成,EndInvoke将一直阻塞到异步调用完成。EndInvoke的参数包括你需要异步执行的方法的outref参数以及由BeginInvoke返回的IAsyncResult

//声明委托
public delegate void AsyncEventHandler();
//异步方法
void Event1()
{Console.WriteLine("Event1 Start");System.Threading.Thread.Sleep(4000);Console.WriteLine("Event1 End");
}// 同步方法
void Event2()
{Console.WriteLine("Event2 Start");int i=1;while(i<1000){i=i+1;Console.WriteLine("Event2 "+i.ToString());}Console.WriteLine("Event2 End");
}static void Main(string[] args)
{long start=0;long end=0;Class1 c = new Class1();Console.WriteLine("ready");start=DateTime.Now.Ticks;//实例委托AsyncEventHandler asy = new AsyncEventHandler(c.Event1);//异步调用开始,没有回调函数和AsyncState,都为nullIAsyncResult ia = asy.BeginInvoke(null, null);//同步开始,c.Event2();//异步结束,若没有结束,一直阻塞到调用完成,在此返回该函数的return,若有返回值。asy.EndInvoke(ia);//都同步的情况。end =DateTime.Now.Ticks;Console.WriteLine("时间刻度差="+ Convert.ToString(end-start) );Console.ReadLine();
}

四、总结

上面说过,.net framework 可以异步调用任何方法。所以异步用处广泛。

在.net framework 类库中也有很多异步调用的方法。一般都是已Begin开头End结尾构成一对,异步委托方法,外加两个回调函数和AsyncState参数,组成异步操作的宏观体现。所以要做异步编程,不要忘了委托delegate、Begin,End,AsyncCallBack委托,AsyncState实例(在回调函数中通过IAsyncResult.AsyncState来强制转换),IAsycResult(监控异步),就足以理解异步真谛了。

这篇关于【.NET Core】多线程之线程池(ThreadPool)详解(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/635353

相关文章

Python函数作用域示例详解

《Python函数作用域示例详解》本文介绍了Python中的LEGB作用域规则,详细解析了变量查找的四个层级,通过具体代码示例,展示了各层级的变量访问规则和特性,对python函数作用域相关知识感兴趣... 目录一、LEGB 规则二、作用域实例2.1 局部作用域(Local)2.2 闭包作用域(Enclos

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

mysql表操作与查询功能详解

《mysql表操作与查询功能详解》本文系统讲解MySQL表操作与查询,涵盖创建、修改、复制表语法,基本查询结构及WHERE、GROUPBY等子句,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随... 目录01.表的操作1.1表操作概览1.2创建表1.3修改表1.4复制表02.基本查询操作2.1 SE

MySQL中的锁机制详解之全局锁,表级锁,行级锁

《MySQL中的锁机制详解之全局锁,表级锁,行级锁》MySQL锁机制通过全局、表级、行级锁控制并发,保障数据一致性与隔离性,全局锁适用于全库备份,表级锁适合读多写少场景,行级锁(InnoDB)实现高并... 目录一、锁机制基础:从并发问题到锁分类1.1 并发访问的三大问题1.2 锁的核心作用1.3 锁粒度分

MySQL数据库中ENUM的用法是什么详解

《MySQL数据库中ENUM的用法是什么详解》ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用,下面:本文主要介绍MySQL数据库中ENUM的用法是什么的相关资料,文中通过代码... 目录mysql 中 ENUM 的用法一、ENUM 的定义与语法二、ENUM 的特点三、ENUM 的用法1

MySQL count()聚合函数详解

《MySQLcount()聚合函数详解》MySQL中的COUNT()函数,它是SQL中最常用的聚合函数之一,用于计算表中符合特定条件的行数,本文给大家介绍MySQLcount()聚合函数,感兴趣的朋... 目录核心功能语法形式重要特性与行为如何选择使用哪种形式?总结深入剖析一下 mysql 中的 COUNT