一、CLR线程池基础

创建和销毁线程是一个昂贵的操作,所以CLR管理了一个线程池(thread pool),可以将线程池看成一个黑盒。

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

二、 ThreadPool的简单使用

可以直接将一个运算放到线程池的队列中进行工作;

2.1 调用方式

向线程池的队列中添加一个”工作项“以及可选的状态数据,可以通过下面的两种方式来进行异步的操作:

public static bool QueueUserWorkItem(WaitCallback callBack);

public static bool QueueUserWorkItem(WaitCallback callBack, object state);

2.2 使用示例

  {
public static void Excute()
{
Console.WriteLine("Main Thread:开始队列进入一个异步线程;");
ThreadPool.QueueUserWorkItem(ComputeBoundOp, 5);
Console.WriteLine("Main Thread:做主线程的其他任务任务;");
//模拟其他任务
Thread.Sleep(10000);
Console.WriteLine("Main Thread End;");
} private static void ComputeBoundOp(object state)
{
Console.WriteLine("In ComputeBoundOp: state={0}",state); //模拟其他任务
Thread.Sleep(20000);
Console.WriteLine("ComputeBoundOp Thread End;");
}
}

运行结果:

2.3 取消线程的操作
简单的操作实例
  public class CancellationDemo
{
/// <summary>
/// 构造一个CancellationTokenSource后,从它的Token属性中获得一个或多个CancellationToken实例,并传给你的操作,使操作可以取消
/// </summary>
public static void CancellationGo()
{
//构造一个CancellationTokenSource
CancellationTokenSource cts =new CancellationTokenSource(); //取消后的执行操作
cts.Token.Register(() => Console.WriteLine("canceled 1"));
cts.Token.Register(() => Console.WriteLine("canceled 2")); //放入线程池开始工作
ThreadPool.QueueUserWorkItem(x => Count(cts.Token, 100)); Console.WriteLine("press to cancel the operation");
Console.ReadLine();
cts.Cancel();
} /// <summary>
/// 计数
/// </summary>
/// <param name="token"></param>
/// <param name="countTo"></param>
private static void Count(CancellationToken token,Int32 countTo)
{
for (int i = 0; i < countTo; i++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("count is cancelled");
break;
}
Console.WriteLine(i);
Thread.Sleep(2000);
}
Console.WriteLine("count is done");
}
}

运行结果:

三、Task

很容易调用ThreadPool的QueueUserWorkItem方法发起一次异步的运算;但是,没有内建的机制让你知道操作在什么时候完成,也没有机制在操作完成时获得返回值;为了克服一些限制,引入了任务概念;

Task类是封装的一个任务类,内部使用的是ThreadPool类,提供了内建机制,让你知道什么时候异步完成以及如何获取异步执行的结果,并且还能取消异步执行的任务。

3.1 使用task和ThreadPool来完成相同的任务:

ThreadPool.QueueUserWorkItem(ComputeBoundOp, 5);

new Task(ComputeBoundOp,5).Start();

Task.Run(() => ComputeBoundOp(5));

3.2 Task的简单使用

public class TaskDemo
{
public void Excute()
{
long input = 10000000;
//创建一个task
Task<Int64> t1 = new Task<Int64>((x) => Sum((Int64) x),
input);
t1.Start(); //显示等待任务执行完毕
t1.Wait();
Console.WriteLine("task1 result is {0},主线程Id:{1}", t1.Result,Thread.CurrentThread.ManagedThreadId); //演示可以取消的任务
CancellationTokenSource cst=new CancellationTokenSource();
//创建一个task
Task<Int64> t2 = new Task<Int64>(()=> Sum(cst.Token,input));
t2.Start();
Thread.Sleep(1000);
cst.Cancel();
Console.WriteLine("task2 result is {0}", t2.Result); } private static Int64 Sum(Int64 n)
{
Int64 sum = 0;
for (;n>0; n--)
{
checked
{
sum += n;
}
}
Console.WriteLine("计算线程Id:{0}",Thread.CurrentThread.ManagedThreadId);
return sum;
} //创建可取消的任务
private static Int64 Sum(CancellationToken ct, Int64 n)
{
Int64 sum = 0;
for (; n > 0; n--)
{
// ct.ThrowIfCancellationRequested();
if (!ct.IsCancellationRequested)
{
checked
{
sum += n;
}
Thread.Sleep(10);
}
}
return sum;
}
}

运行结果:



我们可以发现,程序启动了一个新的线程来计算;

当我们添加了取消操作时,运算结果不同;

四、async和await

在.NET 4.5中引入的Async和Await两个新的关键字后,用户能以一种简洁直观的方式实现异步编程。甚至都不需要改变代码的逻辑结构,就能将原来的同步函数改造为异步函数。

在内部实现上,Async和Await这两个关键字由编译器转换为状态机,通过System.Threading.Tasks中的并行类实现代码的异步执行。

4.1 一个简单的例子

public  class DownLoadUrlAsync
{ public void Excute()
{
Console.WriteLine("this is before Excute,threadId is {0}", Thread.CurrentThread.ManagedThreadId);
var t = GetUrl().ContinueWith(task =>
{
Console.WriteLine("this is ContinueWith Excute,threadId is {0},result is {1}",
Thread.CurrentThread.ManagedThreadId, task.Result);
});
Console.WriteLine("this is Excute,threadId is {0},t IsCompleted is {1}", Thread.CurrentThread.ManagedThreadId,t.IsCompleted);
}
private static async Task<int> GetUrl()
{
var httpClient = new HttpClient(); var url = "https://www.cnblogs.com/";
Console.WriteLine("this is before GetUrl,threadId is {0}", Thread.CurrentThread.ManagedThreadId);
var res = await httpClient.GetByteArrayAsync(url);
Console.WriteLine("this is GetUrl,threadId is {0}", Thread.CurrentThread.ManagedThreadId);
return res.Length;
}
}

运行结果:

通过结果可以发现,程序启用了新的线程来完成我们的任务;

五、小结

1、C#可以使用多种语法实现多线程 Thread,ThreadPool,Task,async await;

2、多线程可以同时完成多个任务;可以使程序的响应速度更快;可以让占用大量处理时间的任务或当前没有进行处理的任务定期将处理时间让给别的任务;

C#多线程的简单理解的更多相关文章

  1. iOS 多线程的简单理解(4) 线程锁的简单使用

    要用到多线程 ,就不得不考虑,线程之间的交互,线程是否安全 推荐一个原文链接 是关于 线程锁的基本使用的  http://blog.csdn.net/qq_30513483/article/detai ...

  2. iOS 多线程的简单理解(1) 方式 :同步 异步

    最近遇到特别糟糕的面试,过程中提到多次对多线程的处理问题,并没有很好的给予答复和解决,所以在这里做个简单的备案: 期望能更加了解和熟练使用 多线程技术: 下面都是自己的总结,如果存在不对的,或者不足, ...

  3. iOS 多线程的简单理解(3)执行方式 + 执行对列 的组合

    通过对前面两偏线程理解的总结,自己对线程的理解也逐渐加深,梳理的清晰起来…… 通常在使用线程 的时候,都是要用到 执行对列,执行方式,执行任务, 现在开始新一轮的深入 3. 1. 1  同步 + 串行 ...

  4. iOS 多线程的简单理解(2) 队列 :串行 ,并行,MainQueue,GlobalQueue

    多线程队列是装载线程任务的队形结构.(系统以先进先出的方式调度队列中的任务执行 FIFO).在GCD中有两种队列: 串行队列.并发队列. 队列 :串行队列.并发队列,全局主对列,全局并发队列 2.1. ...

  5. cpu个数、核数、线程数、Java多线程关系的理解

    cpu个数.核数.线程数.Java多线程关系的理解 2017年12月08日 15:35:37 一 cpu个数.核数.线程数的关系 cpu个数:是指物理上,也及硬件上的核心数: 核数:是逻辑上的,简单理 ...

  6. 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制

    [原创]分布式之数据库和缓存双写一致性方案解析(三)   正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...

  7. input屏蔽历史记录 ;function($,undefined) 前面的分号是什么用处 JSON 和 JSONP 两兄弟 document.body.scrollTop与document.documentElement.scrollTop兼容 URL中的# 网站性能优化 前端必知的ajax 简单理解同步与异步 那些年,我们被耍过的bug——has

    input屏蔽历史记录   设置input的扩展属性autocomplete 为off即可 ;function($,undefined) 前面的分号是什么用处   ;(function($){$.ex ...

  8. 关于 Promise 的一些简单理解

    一.ES6 中的 Promise 1.JS 如何解决 异步问题? (1)什么是 同步.异步? 同步指的是 需要等待 前一个处理 完成,才会进行 下一个处理. 异步指的是 不需要等待 前一个处理 完成, ...

  9. git的简单理解及基础操作命令

    前端小白一枚,最近开始使用git,于是花了2天看了廖雪峰的git教程(偏实践,对于学习git的基础操作很有帮助哦),也在看<git版本控制管理>这本书(偏理论,内容完善,很不错),针对所学 ...

随机推荐

  1. <JavaScript>constructor、prototype、__proto__和原型链

    在看了网上很多相关的文章,很多都是懵逼看完,并不是说各位前辈们写得不好,而是说实在不容易在一两次阅读中理解透.我在阅读了一些文章后,自己整理总结和绘制了一些相关的图,个人认为会更容易接受和理解,所以分 ...

  2. zblog模板怎么安装?zblog主题安装教程

    有很多初次使用zblog的新手还会问我“zblog模板怎么安装?”,那么本文就专门给大家介绍下zblog主题安装教程. zblog现在分为zblogasp和zblogphp两个版本,两个版本的模板主题 ...

  3. jenkins+sonar发送结果邮件的状态问题修复

    在我的这篇博文中:使用jenkins+sonar进行代码扫描,并发送自定义邮件 邮件的配置为默认的$PROJECT_DEFAULT_SUBJECT 所以发送的邮件标题中的状态是jenkins构建的状态 ...

  4. eclipse界面

    Eclipse工作空间的基本配置 A:行号的显示和隐藏 显示:在代码区域的最左边的空白区域,右键 -- Show Line Numbers即可. 隐藏:把上面的动作再做一次. B:字体大小及颜色 a: ...

  5. 泛微E-cology OA /weaver/ 代码执行漏洞

    泛微E-cology OA /weaver/代码执行漏洞 泛微e-cology OA Beanshell组件远程代码执行 分析文章:https://dwz.cn/bYtnsKwa http://127 ...

  6. nvm 相关命令

    nvm install 安装指定版本,可模糊安装,如:安装v10.4.0,既可nvm install v10.4.0,又可nvm install 4.4 nvm uninstall 删除已安装的指定版 ...

  7. SQLServer 查询view中是否包含某个关键字

    在数据库view的创建中,会遇到一些跨数据库的view脚本,但是在将view更新到production的时候可能忘记更改database name,导致出现一些问题. 以下脚本可以检查出包含某个关键字 ...

  8. 题目21 包含Min函数的栈

    ///////////////////////////////////////////////////////////////////////////////////// // 3. 题目21  包含 ...

  9. 使用寄存器点亮LED(第1节)—GPIO功能框图讲解

    GPIO简介 GPIO 是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚, STM32 芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯.控制以及数据采集的功能.STM32 ...

  10. 【hash】Similarity of Subtrees

    图片来源: https://blog.csdn.net/dylan_frank/article/details/78177368 [题意]: 对于每一个节点来说有多少对相同的子树. [题解]: 利用层 ...