本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/18/ThreadPool.html,记录一下学习过程以备后续查用。

、线程池基础

首先,创建和销毁线程是一个要耗费大量时间的过程,其次,太多的线程也会浪费内存资源,所以通过Thread类来创建过多的线程反而有损于性能。为了改善这样

的问题 ,.NET中就引入了线程池。

线程池形象的表示就是存放应用程序中使用的线程的一个集合(就是放线程的地方,这样线程都放在一个地方就好管理了)。

CLR初始化时,线程池中是没有线程的,在内部, 线程池维护了一个操作请求队列。当应用程序想执行一个异步操作时,就调用一个方法,将一个任务放到线程池

的队列中,线程池代码从队列中提取任务,将这个任务委派给一个线程池线程去执行,当线程池线程完成任务时,线程不会被销毁,而是返回到线程池中,等待响应另

一个请求。由于线程不被销毁, 这样就可以避免因为创建线程所产生的性能损失。

MSDN表述:

“线程池经常用在服务器应用程序中,每一个新进来的需求被分配给一个线程池中的线程,这样该需求能被异步的执行,没有阻碍主线程或推迟后继需求的处理。”

    注意:通过线程池创建的线程默认为后台线程,优先级默认为Normal。

    二、通过线程池的工作者线程实现异步

2.1创建工作者线程的方法

public static bool QueueUserWorkItem (WaitCallback callback);

public static bool QueueUserWorkItem(WaitCallback callback, Object state);

这两个方法向线程池的队列添加一个工作项(work item)以及一个可选的状态数据,然后,这两个方法就会立即返回。

工作项其实就是由callback参数标识的一个方法,该方法将由线程池线程执行。同时写的回调方法必须匹配System.Threading.WaitCallback委托类型,定义为:

public delegate void WaitCallback(Object state);

下面演示如何通过线程池线程来实现异步调用:

    class Program
{
static void Main(string[] args)
{
#region 通过线程池的工作者线程实现异步
//设置线程池中工作者线程最大数量为1000,I/O线程最大数量为1000。
ThreadPool.SetMaxThreads(, );
Console.WriteLine("Main thread: queue an asynchronous method.");
PrintMessage("Main thread start."); //把工作项添加到队列中,此时线程池会用工作者线程去执行回调方法。
ThreadPool.QueueUserWorkItem(AsyncMethod);
Console.Read();
#endregion
} /// <summary>
/// 打印线程池信息
/// </summary>
/// <param name="data"></param>
private static void PrintMessage(string data)
{
//获得线程池中可用的工作者线程数量及I/O线程数量
ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
data,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsBackground.ToString(),
workThreadNumber.ToString(),
ioThreadNumber.ToString());
} /// <summary>
/// 异步方法:必须匹配WaitCallback委托
/// </summary>
/// <param name="state"></param>
private static void AsyncMethod(object state)
{
Thread.Sleep();
PrintMessage("Asynchoronous method.");
Console.WriteLine("Asynchoronous thread has worked.");
}
}

运行结果如下:

从结果中可以看出,线程池中的可用的工作者线程少了一个,用去执行回调方法了。

ThreadPool.QueueUserWorkItem(WaitCallback callback,Object state) 方法可以把object对象作为参数传送到回调函数中,使用方法与

ThreadPool.QueueUserWorkItem(WaitCallback callback)类似,这里就不列出了。

    2.2 协作式取消

.NET Framework提供了取消操作的模式, 这个模式是协作式的。为了取消一个操作,首先必须创建一个System.Threading.CancellationTokenSource对象。

下面代码演示协作式取消的使用,主要实现当用户在控制台敲下回车键后就停止数数方法。

    class Program
{
static void Main(string[] args)
{
#region 协作式取消
ThreadPool.SetMaxThreads(, );
Console.WriteLine("Main thread run.");
PrintMessage("Start");
Run();
Console.ReadKey();
#endregion
} /// <summary>
/// 打印线程池信息
/// </summary>
/// <param name="data"></param>
private static void PrintMessage(string data)
{
//获得线程池中可用的工作者线程数量及I/O线程数量
ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
data,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsBackground.ToString(),
workThreadNumber.ToString(),
ioThreadNumber.ToString());
} /// <summary>
/// 运行工作者线程(包含协作式取消)
/// </summary>
private static void Run()
{
CancellationTokenSource cts = new CancellationTokenSource(); //这里是用Lambda表达式的写法,效果一样。
//ThreadPool.QueueUserWorkItem(obj => Count(cts.Token, 1000)); ThreadPool.QueueUserWorkItem(Callback, cts.Token);
Console.WriteLine("Press enter key to cancel the operation.\n");
Console.ReadLine();
//传达取消请求
cts.Cancel();
} /// <summary>
/// 回调函数
/// </summary>
/// <param name="state"></param>
private static void Callback(object state)
{
Thread.Sleep();
PrintMessage("Asynchoronous method start.");
CancellationToken token = (CancellationToken)state;
Count(token, );
} /// <summary>
/// 数数
/// </summary>
/// <param name="token"></param>
/// <param name="countTo"></param>
private static void Count(CancellationToken token, int countTo)
{
for (int i = 1; i <= countTo; i++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Count is canceled.");
break;
} Console.WriteLine(i);
Thread.Sleep();
}
Console.WriteLine("Count has done.");
}
}

运行结果如下:

、使用委托实现异步

    涉及术语解释--异步编程模型:

APM 异步编程模型(Asynchronous Programming Model)

EAP 基于事件的异步编程模式(Event-based Asynchronous Pattern)

TAP 基于任务的异步编程模式(Task-based Asynchronous Pattern)

通过调用ThreadPool的QueueUserWorkItem方法来来启动工作者线程非常方便,但委托WaitCallback指向的是带有一个参数的无返回值的方法。如果我们实际操作中

需要有返回值,或者需要带有多个参数, 这时通过这样的方式就难以实现了。 为了解决这样的问题,我们可以通过委托来建立工作这线程。

下面代码演示使用委托实现异步:

    class Program
{
//使用委托实现异步,是使用了异步编程模型APM。
private delegate string ThreadDelegate(); static void Main(string[] args)
{
#region 使用委托实现异步
ThreadPool.SetMaxThreads(, );
PrintMessage("Main thread start."); //实例化委托
ThreadDelegate threadDelegate = new ThreadDelegate(AsyncMethod);
//异步调用委托
IAsyncResult result = threadDelegate.BeginInvoke(null, null);
//获取结果并打印
string returnData = threadDelegate.EndInvoke(result);
Console.WriteLine(returnData);
Console.ReadLine();
#endregion
} /// <summary>
/// 打印线程池信息
/// </summary>
/// <param name="data"></param>
private static void PrintMessage(string data)
{
//获得线程池中可用的工作者线程数量及I/O线程数量
ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
data,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsBackground.ToString(),
workThreadNumber.ToString(),
ioThreadNumber.ToString());
} /// <summary>
/// 异步方法
/// </summary>
/// <returns></returns>
private static string AsyncMethod()
{
Thread.Sleep();
PrintMessage("Asynchoronous method.");
return "Method has completed.";
}
}

运行结果如下:

    四、任务

同样,任务的引入也是为了解决通过ThreadPool.QueueUserWorkItem中限制的问题。

    4.1 使用任务来实现异步

    class Program
{
static void Main(string[] args)
{
#region 使用任务实现异步
ThreadPool.SetMaxThreads(, );
PrintMessage("Main thread start.");
//调用构造函数创建Task对象
Task<int> task = new Task<int>(n => AsyncMethod((int)n), ); //启动任务
task.Start();
//等待任务完成
task.Wait();
Console.WriteLine("The method result is: " + task.Result);
Console.ReadLine();
#endregion
} /// <summary>
/// 打印线程池信息
/// </summary>
/// <param name="data"></param>
private static void PrintMessage(string data)
{
//获得线程池中可用的工作者线程数量及I/O线程数量
ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
data,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsBackground.ToString(),
workThreadNumber.ToString(),
ioThreadNumber.ToString());
} /// <summary>
/// 异步方法
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
private static int AsyncMethod(int n)
{
Thread.Sleep();
PrintMessage("Asynchoronous method."); int sum = ;
for (int i = ; i < n; i++)
{
//运算溢出检查
checked
{
sum += i;
}
} return sum;
}
}

运行结果如下:

    4.2 取消任务

如果要取消任务, 同样也可以CancellationTokenSource对象来取消。

下面代码演示取消一个任务:

    class Program
{
static void Main(string[] args)
{
#region 取消任务
ThreadPool.SetMaxThreads(, );
PrintMessage("Main thread start.");
CancellationTokenSource cts = new CancellationTokenSource(); //调用构造函数创建Task对象,将一个CancellationToken传给Task构造器从而使Task和CancellationToken关联起来。
Task<int> task = new Task<int>(n => AsyncMethod(cts.Token, (int)n), ); //启动任务
task.Start();
//延迟取消任务
Thread.Sleep(); //取消任务
cts.Cancel();
Console.WriteLine("The method result is: " + task.Result);
Console.ReadLine();
#endregion
} /// <summary>
/// 打印线程池信息
/// </summary>
/// <param name="data"></param>
private static void PrintMessage(string data)
{
//获得线程池中可用的工作者线程数量及I/O线程数量
ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
data,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsBackground.ToString(),
workThreadNumber.ToString(),
ioThreadNumber.ToString());
} /// <summary>
/// 异步方法
/// </summary>
/// <param name="ct"></param>
/// <param name="n"></param>
/// <returns></returns>
private static int AsyncMethod(CancellationToken ct, int n)
{
Thread.Sleep();
PrintMessage("Asynchoronous method."); int sum = ;
try
{
for (int i = ; i < n; i++)
{
//当CancellationTokenSource对象调用Cancel方法时,就会引起OperationCanceledException异常,
//通过调用CancellationToken的ThrowIfCancellationRequested方法来定时检查操作是否已经取消,
//这个方法和CancellationToken的IsCancellationRequested属性类似。
ct.ThrowIfCancellationRequested();
Thread.Sleep();
//运算溢出检查
checked
{
sum += i;
}
}
}
catch (Exception e)
{
Console.WriteLine("Exception is:" + e.GetType().Name);
Console.WriteLine("Operation is canceled.");
} return sum;
}
}

运算结果如下:

4.3 使用任务工厂实现异步操作

同样也可以通过任务工厂TaskFactory类型来实现异步操作。

    class Program
{
static void Main(string[] args)
{
#region 使用任务工厂实现异步
ThreadPool.SetMaxThreads(, );
Task.Factory.StartNew(() => PrintMessage("Main thread."));
Console.Read();
#endregion
} /// <summary>
/// 打印线程池信息
/// </summary>
/// <param name="data"></param>
private static void PrintMessage(string data)
{
//获得线程池中可用的工作者线程数量及I/O线程数量
ThreadPool.GetAvailableThreads(out int workThreadNumber, out int ioThreadNumber); Console.WriteLine("{0}\n CurrentThreadId is:{1}\n CurrentThread is background:{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is:{4}\n",
data,
Thread.CurrentThread.ManagedThreadId,
Thread.CurrentThread.IsBackground.ToString(),
workThreadNumber.ToString(),
ioThreadNumber.ToString());
}
}

运行结果如下:

 

最新文章

  1. how2heap分析系列:2_fastbin_dup
  2. C++ cast
  3. Acer-宏碁电脑BOIS
  4. mac 升级vim
  5. WindowsPhone-GameBoy模拟器开发六--[转]指令系统实现必读:补码
  6. Java-try-catch-finally
  7. Oracle基础&lt;5&gt;--触发器
  8. 【Hibernate总结系列】....hbm.xml配置
  9. liunx命令之whereis、which、find的区别和联系
  10. ubuntu14.04.2 添加ppa remastersys源 镜像ubuntu系统
  11. redis 控制调用频率
  12. Spring的注解学习(ioc,aop结合)
  13. 【Arduino】8地点LED数码管(3461BS)
  14. load和DOMContenLoaded的区别
  15. cookie 使用方法
  16. 近期ubuntu 14.04 cpu占用高排障
  17. 「洛谷3870」「TJOI2009」开关【线段树】
  18. Autofac使用
  19. Lua中string.format占位符的使用
  20. Java多线程入门中几个常用的方法

热门文章

  1. 使用IDEA开发Spring入门程序
  2. P1387 最大正方形 |动态规划
  3. 开发中遇到的一些bug及解决方案
  4. IOS之文件夹创建、删除,图片在本地的保存和加载
  5. git 使用详解(9)-- 分支的新建与合并 git branch -d、merge、 --merged/--no-merged/-v
  6. Spring Boot结和Spring Data(Ehcache缓存,Thymeleaf页面,自定义异常页面跳转,Swagger2)
  7. 强化学习环境OpenAi搭建,从虚拟机到Gym、Mujoco和mujoco-py的完整安装
  8. CORS on Nginx
  9. unity3d WeelCollider 漂移
  10. Jmeter介绍以及脚本制作与调试