广州网站建设排行,html5网页设计源代码,苏州市优化网站推广哪家好,珠海斗门建设局官方网站阅读目录 代码下载一、介绍二、通过TPL进入线程池三、不用TPL进入到线程池v博客前言 先交代下背景#xff0c;写《C#多线程之旅》这个系列文章主要是因为以下几个原因#xff1a;1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的#xff0c;如果没有… 阅读目录 代码下载一、介绍二、通过TPL进入线程池三、不用TPL进入到线程池v博客前言 先交代下背景写《C#多线程之旅》这个系列文章主要是因为以下几个原因1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非常复杂的如果没有用好容易造成很多问题。 v写在前面
多线程有利也有弊使用需谨慎。
v正文开始 代码下载
Thread_博客园_cnblogs_jackson0714.zip
第一篇~第三篇的代码示例 源码地址https://github.com/Jackson0714/Threads
回到顶部
一、介绍
无论你什么时候开始一个线程几百毫秒会花在整理一个新的local variable stack。每一个线程默认会消耗1MB的内存。线程池通过分享和回收线程来削减这些开销允许多线程被应用在一个非常颗粒级的级别而没有性能损失。当充分利用多核系统去执行密集型计算的并行代码时这是非常有用的。
线程池也会在线程的总数量上保持一个限制从而使线程能够更平稳地运行。太多的线程将会造成管理负担和使CPU缓存是小从而造成操作系统不能运行。一旦一个限制到达job排队等待直到另外一个完成才开始。这会使任意的并行应用程序成为可能比如一个web server同步方法是高级技巧可以更高效地使用线程池中的线程。
下面是几种方式进入线程池
通过Task Parallel Library.NET 4.0通过调用ThreadPool.QueueUserWorkItem通过asynchronous delegates通过BackgroundWorkder
下面的结构直接使用线程池
WCF,Remoting,ASP.NET,ASMX Web Services application serversSystem.Timers.Timer and System.Threading.TimerFramework methods 由Async结束比如WebClient(the event-based asynchronous pattern)和大部分的BeginXXX方法(the asynchronous programming model pattern)PLINQ
Task Parallel Library(TPL)和PLINQ是充分有效的和高等级的甚至当线程池是不重要的时候你也会想使用它们去协助处理多线程。
现在我们简单的看一下我们怎样使用Task类来实现一个简单的运行在线程池上的委托。
当使用线程池时需要注意下面的事情
你不能设置一个线程的名字因为设置线程的名字将会使调试更困难当你在VS线程窗口中调试时即使你可以附加一个描述。线程池中的线程总是后台线程这通常不是问题。在应用程序的开始期间阻塞一个线程可能会触发一个延迟除非你调用ThreadPool.SetMinThreads
你不能任意地改变池中的线程的优先级-因为当它释放会池中的时候优先级会被还原为正常状态。
你可以通过属性Thread.CurrentThread.IsThreadPoolThread的属性查询线程是否是正在运行的一个池中的线程
回到顶部
二、通过TPL进入线程池
你可以使用在TaskParallel Library中的Task类来轻松的进入线程池。这个Task类在Framework 4.0中有介绍如果你对老的结构比较熟悉考虑用非泛型的Task类替换ThreadPool.QueueUserWorkItem将Asunchoronous delgates替换为泛型TaskTResult。最新的结构速度更快更方便而且更复杂。
为了使用非泛型的任务类调用Task.Factory.StartNew方法将方法传进委托中。
Task.Factory.StartNew会返回一个Task对象你可以使用它去监控这个task比如你可以调用它的wait方法等待它直到它完成。 1 2 3 4 5 6 7 8 9 10 11 12 13 static void Main(string[] args) { Task task Task.Factory.StartNew(Go); task.Wait(); Console.ReadKey(); } static void Go() { Console.WriteLine(From the thread pool start...); Thread.Sleep(3000); Console.WriteLine(From the thread pool end); }
当你调用task的Wait 方法时一个未处理的异常会很容易地重新抛出到宿主线程上。如果你不调用Wait方法而是放弃这个task一个未处理的异常将会关闭掉这个进程
泛型TaskTresult类是非泛型Task的子类。它让你从这个已经完成执行的task中得到一个返回值。在下面的例子中我们使用TaskTResult来下载一个web page 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 static void Main(string[] args) { Taskstring task Task.Factory.StartNewstring( () DownloadString(http://www.baidu.com)); //调用其他方法 // //可以用task的Result的属性来获得task返回值。 //如果这个任务还在运行当前的主线程将会被阻塞直到这个任务完成。 string result task.Result; } static string DownloadString(string uri) { using(var wc new System.Net.WebClient()) { return wc.DownloadString(uri); } }
Task Parallel Library有许多的功能特别是提升多核处理器的性能。我们会在并行编程中继续讨论TPL。
回到顶部
三、不用TPL进入到线程池
如果你的应用程序是.NET Framework的早期版本4.0之前的版本你将不能使用TPL。你必须使用老的结构进入线程池
ThreadPool.QueueUserWorkItem和asynchoronous delegates.两者的不同点是asynchronous delegates让你从线程那里返回数据。Asynchronous delegates收集任何exception返回给调用者。
要使用QueueUserWorkItem只需调用这个方法的运行在线程池上的委托。 1 2 3 4 5 6 7 8 9 10 11 static void Main(string[] args) { ThreadPool.QueueUserWorkItem(Go); ThreadPool.QueueUserWorkItem(Go, 123); Console.ReadKey(); } static void Go(object data) { Console.WriteLine(A from thread pool! data); } 我们的目标方法Go必须接收一个简单object类型的参数为了满足waitCallBack委托。这将提供一个简单的方式传递数据到方法中就像是ParameterizedThreadStart。不像TaskQueueUserWorkItem不会返回一个对象去帮助你之后管理执行。还有你必须显式在目标方法的代码中写处理异常的代码-因为未处理的异常将会终止程序。 ThreadPool.QueueUserWorkItem没有提供从一个已经完成的线程中得到它的返回值的机制。Asynchronous delegate invocations(asynchronous delegates for short)解决了这个问题允许任何个数类型化的参数在两个方向传递。此外在asynchronous delegates上未处理的异常很方便地在原始线程上重新抛出更准确地说这个线程叫做EndInvoke,因此不需要显示处理。
不要混淆asynchronous delegates和asynchronous method方法以Begin和End开头的比如File.BeginRead/File.EndRead。Asynchronous methods表面上按照简单的协议但是它们的存在是为了解决一个更困难的问题。
下面是怎样通过一个asynchronous delegate开始一个worker task:
实例化一个委托该委托针对你想要并行运行的method典型的是预定义Func delegates其中的一种。在delegate上调用BeginInvoke保存它的IAsyncResult返回值。BeginInvoke立即返回给调用者。当其他池中的线程正在运行的时候你可以执行其他动作。当你需要这个结果在delegate上调用EndInvoke传递已保存的IAsyncResult对象。
在下面的例子中我们使用一个asynchronous delegate invocation运行一个与主线程同时运行的简单方法这个方法返回一个字符串的长度 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 static void Main(string[] args) { Funcstring, int t Go; IAsyncResult result t.BeginInvoke(test, null, null); // // ... 这里可以执行其他并行的任务 // int length t.EndInvoke(result); Console.WriteLine(String lenth is length); Console.ReadKey(); } static int Go(string messsage) { return messsage.Length; }
EndInvoke做三件事情。第一如果asynchronous delegate没有完成执行则一直等待它完成。第二接收返回值以及任何ref或者out参数。第三返回任何未处理的线程异常给调用它的线程。
注意如果你用asynchronous delegate调用的方法没有返回值你在技术上需要调用EndInvoke。在实践中这是开放的辩论没有Endinvoke报警去管理处罚未编译者如果你选择不去调用EndInvoke然而你需要考虑在线程的异常去避免静默失败。
当你调用BeginInvoke方法时可以指定一个call back delegate-一个可以接收一个IAsyncResult 对象的方法它会在委托方法完成后被自动调用这个允许正在发动的线程忘记asynchronous delegate但它在call back结束时需要一点额外的工作。
v写在最后 线程池的使用的提升还没有写最近两年作息不规律程序员得养好身体早睡早起睡觉睡觉。希望这篇博客能帮到大家希望得到园友们的支持 作 者 Jackson0714 出 处http://www.cnblogs.com/jackson0714/ 关于作者专注于微软平台的项目开发。如有问题或建议请多多赐教 版权声明本文版权归作者和博客园共有欢迎转载但未经作者同意必须保留此段声明且在文章页面明显位置给出原文链接。 特此声明所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误共同进步。或者直接私信我