[.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(三) 利用多线程提高程序性能(下)
[.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(二) 利用多线程提高程序性能(下)
本节导读:
上节说了线程同步中使用线程锁和线程通知的方式来处理资源共享问题,这些是多线程的基本原理。
.NET 4.0以后对多线程的实现变得更简单了。
本节主要讨论.NET4.0多线程的新特性——使用Task类创建多线程。
读前必备:
A. LINQ使用 [.net 面向对象编程基础] (20) LINQ使用
B. 泛型 [.net 面向对象编程基础] (18) 泛型
1. 线程池ThreadPool
在介绍4.0以后的多线程新特征之前,先简单说一下线程池。
通过前面对多线程的学习,我们发现多线程的创建和使用并不难,难的在于多线程的管理,特别是线程数量级很多的情况下,如何进行管理和资源释放。需要使用线程池来解决。
简单来说线程池就是.NET提供的存放线程的一个对象容器。
线程池线程分为两类:工作线程和IO线程.
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。
对于线程池,可使用要运行的过程的委托调用 System.Threading.ThreadPool.QueueUserWorkItem(System.Threading.WaitCallback) 方法
下面是一个线程池的示例:
先设置一个创建线程总数静态字段:
static readonly int totalThreads = ;
使用线程池创建线程:
//设置最小线程和最大线程数
ThreadPool.SetMinThreads(, );
ThreadPool.SetMaxThreads(, ); for (int i = ; i < totalThreads; i++)
{
ThreadPool.QueueUserWorkItem(o =>
{
Thread.Sleep();
int a, b;
ThreadPool.GetAvailableThreads(out a, out b);
Console.WriteLine(string.Format("({0}/{1}) #{2} : {3}", a, b, Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString()));
});
}
Console.WriteLine("主线程完成");
运行结果如下:

2. Task类
用ThreadPool的QueueUserWorkItem()方法发起一次异步的线程执行很简单,但是该方法最大的问题是没有一个内建的机制让你知道操作什么时候完成,有没有一个内建的机制在操作完成后获得一个返回值。为此,在.NET 4.0 以后,我们可以使用System.Threading.Tasks中的Task类。这也是.NET 4.0以后多线程的推荐做法。
构造一个Task<T>对象,并为泛型T参数传递一个操作的返回类型。
Task类可以使用多种方法创建多线程,下面详细介绍。
2.1 使用Factory属性
Task 实例可以用各种不同的方式创建。 最常见的方法是使用任务的 Factory 属性检索可用来创建用于多个用途的TaskFactory 实例。
例如,要创建运行操作的 Task,可以使用工厂的 StartNew 方法:
//最简单的线程示例
Task.Factory.StartNew(() =>
{
Console.WriteLine("我是使用Factory属性创建的线程");
});
运行结果如下:

如果想简单的创建一个Task,那么使用Factory.NewStart()来创建,很简便。
如果像对所创建的Task附加更多的定制和设置特定的属性,请继续往下看。
2.2 使用Task实例实现多线程
//简单的Task实例创建线程
Action<object> action = (object obj) =>
{
Console.WriteLine("Task={0}, obj={1}, Thread={2}", Task.CurrentId, obj.ToString(), Thread.CurrentThread.ManagedThreadId);
};
Task t1 = new Task(action, "参数");
t1.Start();
运行结果如下:

//简写上面实例,并创建100个线程
System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();
int m = ;
Task[] tasks = new Task[m];
for (int i = ; i < m; i++)
{
tasks[i] = new Task((object obj) =>
{
Thread.Sleep();
Console.WriteLine("Task={0}, obj={1}, Thread={2},当前时间:{3}",
Task.CurrentId, obj.ToString(),
Thread.CurrentThread.ManagedThreadId,
System.DateTime.Now.ToString());
}, "参数" + i.ToString()
);
tasks[i].Start();
} Task.WaitAll(tasks);
Console.WriteLine("线程耗时:{0},当前时间:{1}" ,watch.ElapsedMilliseconds,System.DateTime.Now.ToString());
运行结果如下:

2.3 Task传入参数
上面介绍了使用一个Action委托来完成任程,那么给线程中传入参数,就可以使用System.Action<object>来完成。
传入一个参数的示例:
/// <summary>
/// 一个参数的方法
/// </summary>
/// <param name="parameter"></param>
static void MyMethod(string parameter)
{
Console.WriteLine("{0}", parameter);
}
调用如下:
//Task传入一个参数
Task myTask = new Task((parameter) => MyMethod(parameter.ToString()), "aaa");
myTask.Start();
运行结果如下:

传入多个参数如下:
/// <summary>
/// 多个参数的方法
/// </summary>
/// <param name="parameter1"></param>
/// <param name="parameter2"></param>
/// <param name="parameter3"></param>
static void MyMethod(string parameter1,int parameter2,DateTime parameter3)
{
Console.WriteLine("{0} {1} {2}", parameter1,parameter2.ToString(),parameter3.ToString());
}
调用如下:
//Task传入多个参数
for (int i = ; i <= ; i++)
{
new Task(() => { MyMethod("我的线程", i, DateTime.Now); }).Start();
Thread.Sleep();
}
运行结果如下:

对于传入多个参数,可以使用无参数委托包装一个多参数的方法来完成。
2.4 Task的结果
要获取Task的结果,在创建Task的时候,就要采用Task<T>来实例化一个Task。
其中的T就是Task执行完成之后返回结果的类型。
通过Task实例的Result属性就可以获取结果。
System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();
Task<int> myTask = new Task<int>(() =>
{
int sum = ;
for (int i = ; i < ; i++)
sum += i;
return sum;
});
myTask.Start();
Console.WriteLine("结果: {0} 耗时:{1}", myTask.Result,watch.ElapsedMilliseconds);
运行结果如下:

使用Factory属性来完成上面的示例:
//使用Factory属性创建
System.Diagnostics.Stopwatch watchSecond = System.Diagnostics.Stopwatch.StartNew();
Task<int> myTaskSecond = Task.Factory.StartNew<int>(() =>
{
int sum = ;
for (int i = ; i < ; i++)
sum += i;
return sum;
});
Console.WriteLine("结果: {0} 耗时:{1}", myTaskSecond.Result, watchSecond.ElapsedMilliseconds);
运行结果如下:

多线程除以上的一些基础知识,在处理各种并行任务和多核编程中的使用,小伙伴可以参考专门关于多线程的书籍学习。
想要完全深入的学习多线程需要慢慢修炼,不断积累。
3. 本节要点:
A.本点简单介绍了线程池ThreadPool的使用;
B.介绍一使用Task进行多线程创建及Tast的参数传入和返回结果。
==============================================================================================
<如果对你有帮助,记得点一下推荐哦,如有有不明白或错误之处,请多交流>
<对本系列文章阅读有困难的朋友,请先看《.net 面向对象编程基础》>
<转载声明:技术需要共享精神,欢迎转载本博客中的文章,但请注明版权及URL>
.NET 技术交流群:467189533 
==============================================================================================
[.net 面向对象程序设计进阶] (18) 多线程(Multithreading)(三) 利用多线程提高程序性能(下)的更多相关文章
- [.net 面向对象程序设计进阶] (15) 缓存(Cache)(二) 利用缓存提升程序性能
[.net 面向对象程序设计进阶] (15) 缓存(Cache)(二) 利用缓存提升程序性能 本节导读: 上节说了缓存是以空间来换取时间的技术,介绍了客户端缓存和两种常用服务器缓布,本节主要介绍一种. ...
- [.net 面向对象程序设计进阶] (17) 多线程(Multithreading)(二) 利用多线程提高程序性能(中)
[.net 面向对象程序设计进阶] (17) 多线程(Multithreading)(二) 利用多线程提高程序性能(中) 本节要点: 上节介绍了多线程的基本使用方法和基本应用示例,本节深入介绍.NET ...
- [.net 面向对象程序设计进阶] (16) 多线程(Multithreading)(一) 利用多线程提高程序性能(上)
[.net 面向对象程序设计进阶] (16) 多线程(Multithreading)(一) 利用多线程提高程序性能(上) 本节导读: 随着硬件和网络的高速发展,为多线程(Multithreading) ...
- [.net 面向对象程序设计进阶] (11) 序列化(Serialization)(三) 通过接口 IXmlSerializable 实现XML序列化 及 通用XML类
[.net 面向对象程序设计进阶] (11) 序列化(Serialization)(三) 通过接口 IXmlSerializable 实现XML序列化 及 通用XML类 本节导读:本节主要介绍通过序列 ...
- [.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用
[.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用 本节导读:讨论了表达式树的定义和解析之后,我们知道了表达式树就是并非可执行代码,而是将表达式对象化后的数据结构.是 ...
- [.net 面向对象程序设计进阶] (1) 开篇
[.net 面向对象程序设计进阶] (1) 开篇 上一系列文章<.net 面向对象编程基础>写完后,很多小伙伴们希望我有时间再写一点进阶的文章,于是有了这个系列文章.这一系列的文章中, 对 ...
- [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦
[.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦 本节导读:上篇文章简单介绍了.NET面向对象中一个重要的技术反射的基本应用,它可以让我们动态的调 ...
- [.net 面向对象程序设计进阶] (4) 正则表达式 (三) 表达式助手
[.net 面向对象程序设计进阶] (2) 正则表达式(三) 表达式助手 上面两节对正则表达式的使用及.NET下使用正则表达式作了详细说明,本节主要搜集整理了常用的正则表达式提供参考. 此外为了使用方 ...
- [.net 面向对象程序设计进阶] (24) 团队开发利器(三)使用SVN多分支并行开发(下)
[.net 面向对象程序设计进阶] (24) 团队开发利器(三)使用SVN多分支并行开发(下) 本篇导读: 接上篇继续介绍SVN的高级功能,即使用分支并行开发.随着需求的不断变更,新功能的增加.特别是 ...
随机推荐
- SQL Server 事务以及事务日志综述
事务是一个非常重要的概念,特此在这里写一些文章来总结.整篇文章还在持续更新中. 在本系列文章中,你将看到以下内容: 数据库事务(Database Transaction)概述 事务操作(BEGIN/C ...
- Power BI入门教程
题记:这篇文章不仅是Power BI的入门教程,同时相对于Qlik Sense进行了简单比较. 最近把一个Qlik Sense的示例应用手动转成了Power BI的应用,把相关步骤和遇到的问题记录如下 ...
- 10gRAC vip启动报错CRS-1006 CRS-0215
为测试一个迁移方案,装了一套10g rac环境,可能是很久没有装过10g的RAC了,整个过程情况不断. 1.在把集群软件和数据库软件都装好之后,用crs_stat检测状态的时候,发现vip的状态不对, ...
- c#中ObservableCollection<T>排序方法
之前用到的一段代码,记录一下 public static class ObservableExtension { public static void Sort<TSource, TKey> ...
- POJ 1066 Treasure Hunt (线段相交)
题意:给你一个100*100的正方形,再给你n条线(墙),保证线段一定在正方形内且端点在正方形边界(外墙),最后给你一个正方形内的点(保证不再墙上) 告诉你墙之间(包括外墙)围成了一些小房间,在小房间 ...
- 【转】http头部详解
原地址:http://www.cnblogs.com/ziwuge/archive/2011/09/27/2193385.html HTTP 头部解释 1. Accept:告诉WEB服务器自己接受什么 ...
- 转:MYSQL连接字符串参数解析(解释)
被迫转到MySQL数据库,发现读取数据库时,tinyint类型的值都被转化为boolean了,这样大于1的值都丢失,变成true了.查阅资料MySQL中无Boolean类型,都是存储为tinyint了 ...
- 分布式服务协调技术zookeeper笔记
本文主要学习ZooKeeper的体系结构.节点类型.节点监听.常用命令等基础知识,最后还学习了ZooKeeper的高可用集群的搭建与测试.希望能给想快速掌握ZooKeeper的同学有所帮助. ZooK ...
- Android中Retrifit使用总结
Android中网络请求框架Retrofit的使用注意事项 1.Retrofit是基于OkHttp网络请求框架的二次封装而已,懂Okhttp的小伙伴,那么Retrofit也就基本都会. 2.Retro ...
- Ruby Gem命令详解
转自:http://www.jianshu.com/p/728184da1699 Gem介绍: Gem是一个管理Ruby库和程序的标准包,它通过Ruby Gem(如 http://rubygems.o ...