C#多线程的简单理解
一、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#多线程的简单理解的更多相关文章
- iOS 多线程的简单理解(4) 线程锁的简单使用
要用到多线程 ,就不得不考虑,线程之间的交互,线程是否安全 推荐一个原文链接 是关于 线程锁的基本使用的 http://blog.csdn.net/qq_30513483/article/detai ...
- iOS 多线程的简单理解(1) 方式 :同步 异步
最近遇到特别糟糕的面试,过程中提到多次对多线程的处理问题,并没有很好的给予答复和解决,所以在这里做个简单的备案: 期望能更加了解和熟练使用 多线程技术: 下面都是自己的总结,如果存在不对的,或者不足, ...
- iOS 多线程的简单理解(3)执行方式 + 执行对列 的组合
通过对前面两偏线程理解的总结,自己对线程的理解也逐渐加深,梳理的清晰起来…… 通常在使用线程 的时候,都是要用到 执行对列,执行方式,执行任务, 现在开始新一轮的深入 3. 1. 1 同步 + 串行 ...
- iOS 多线程的简单理解(2) 队列 :串行 ,并行,MainQueue,GlobalQueue
多线程队列是装载线程任务的队形结构.(系统以先进先出的方式调度队列中的任务执行 FIFO).在GCD中有两种队列: 串行队列.并发队列. 队列 :串行队列.并发队列,全局主对列,全局并发队列 2.1. ...
- cpu个数、核数、线程数、Java多线程关系的理解
cpu个数.核数.线程数.Java多线程关系的理解 2017年12月08日 15:35:37 一 cpu个数.核数.线程数的关系 cpu个数:是指物理上,也及硬件上的核心数: 核数:是逻辑上的,简单理 ...
- 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制
[原创]分布式之数据库和缓存双写一致性方案解析(三) 正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...
- input屏蔽历史记录 ;function($,undefined) 前面的分号是什么用处 JSON 和 JSONP 两兄弟 document.body.scrollTop与document.documentElement.scrollTop兼容 URL中的# 网站性能优化 前端必知的ajax 简单理解同步与异步 那些年,我们被耍过的bug——has
input屏蔽历史记录 设置input的扩展属性autocomplete 为off即可 ;function($,undefined) 前面的分号是什么用处 ;(function($){$.ex ...
- 关于 Promise 的一些简单理解
一.ES6 中的 Promise 1.JS 如何解决 异步问题? (1)什么是 同步.异步? 同步指的是 需要等待 前一个处理 完成,才会进行 下一个处理. 异步指的是 不需要等待 前一个处理 完成, ...
- git的简单理解及基础操作命令
前端小白一枚,最近开始使用git,于是花了2天看了廖雪峰的git教程(偏实践,对于学习git的基础操作很有帮助哦),也在看<git版本控制管理>这本书(偏理论,内容完善,很不错),针对所学 ...
随机推荐
- Django 测试开发1
笔者用的版本的是django==1.8.2,这个版本的学习资料最多,文档最完整.首先创建项目:django-admin startproject 项目名. guest/__init__.py 一个空的 ...
- Qt编写自定义控件39-导航标签
一.前言 在很多菜单导航界面中,当单击了二级菜单或者三级菜单以后,顶部会显示带箭头或者其他标识的导航标签,可以单击该标签快速切换到对应的界面,也作为指示当前处于哪一级菜单下的界面,主要在WEB中大肆流 ...
- python 函数、参数及参数解构
函数 数学定义 y=f(x), y是x函数,x是自变量.y=f(x0,x1...xn) Python函数 由若干语句组成的语句块,函数名称,参数列表构成,它是组织代码的最小单位 完成一定的功能 函数作 ...
- for miaomiao
package com.mytest.formiaomiao; import java.util.ArrayList; import java.util.List; import java.util. ...
- droid AVD创建及设置中各参数详解
设置AVD时有些参数比较模糊,特地找了篇文章,大家参考下! 本文根据如下的模拟器安装做一些解释: Name: 自定义虚拟的名称,不能有空格或者其他非法字符,否则不能创建,即Creat AVD不能高亮点 ...
- 【Leetcode_easy】633. Sum of Square Numbers
problem 633. Sum of Square Numbers 题意: solution1: 可以从c的平方根,注意即使c不是平方数,也会返回一个整型数.然后我们判断如果 i*i 等于c,说明c ...
- Python3之类和实例访问限制
在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑. 但是,从前面的Student类定义来看,外部代码还是可以自由地修改一个实例的na ...
- Android Monkey压力测试(转)
参考链接:https://www.cnblogs.com/yyh8/p/6707745.html Monkey 是Android SDK提供的一个命令行工具, 可以简单,方便地运行在任何版本的Andr ...
- 简单的api实现以及动态函数调用
实现一个简单的api功能,环境python2.7 请求方法:curl http://ip:8000/?name={api中的方法名}|python -m json.tool 只需编写api的方法即可 ...
- (CVE-2016-5195)脏牛本地提权
简要分析 该漏洞具体为,get_user_page内核函数在处理Copy-on-Write(以下使用COW表示)的过程中,可能产出竞态条件造成COW过程被破坏, 导致出现写数据到进程地址空间内只读内存 ...