v博客前言
v写在前面 多线程,有利也有弊,使用需谨慎。 v正文开始
原文地址:C#多线程之旅(3)——线程池 C#多线程之旅(5)——同步机制介绍 C#多线程之旅(6)——详解多线程中的锁 更多文章正在更新中,敬请期待...... C#多线程之旅(3)——线程池 代码下载Thread_博客园_cnblogs_jackson0714.zip 第一篇~第三篇的代码示例: 源码地址:https://github.com/Jackson0714/Threads 一、介绍无论你什么时候开始一个线程,几百毫秒会花在整理一个新的local variable stack。每一个线程默认会消耗1MB的内存。线程池通过分享和回收线程来削减这些开销,允许多线程被应用在一个非常颗粒级的级别而没有性能损失。当充分利用多核系统去执行密集型计算的并行代码时这是非常有用的。 线程池也会在线程的总数量上保持一个限制,从而使线程能够更平稳地运行。太多的线程将会造成管理负担和使CPU缓存是小,从而造成操作系统不能运行。一旦一个限制到达,job排队等待直到另外一个完成才开始。这会使任意的并行应用程序成为可能,比如一个web server(同步方法是高级技巧,可以更高效地使用线程池中的线程)。 下面是几种方式进入线程池:
下面的结构直接使用线程池:
Task Parallel Library(TPL)和PLINQ是充分有效的和高等级的,甚至当线程池是不重要的时候,你也会想使用它们去协助处理多线程。 现在我们简单的看一下我们怎样使用Task类来实现一个简单的运行在线程池上的委托。 当使用线程池时需要注意下面的事情:
你不能任意地改变池中的线程的优先级-因为当它释放会池中的时候,优先级会被还原为正常状态。 你可以通过属性Thread.CurrentThread.IsThreadPoolThread的属性查询线程是否是正在运行的一个池中的线程 二、通过TPL进入线程池你可以使用在TaskParallel Library中的Task类来轻松的进入线程池。这个Task类在Framework 4.0中有介绍:如果你对老的结构比较熟悉,考虑用非泛型的Task类替换ThreadPool.QueueUserWorkItem,将Asunchoronous delgates替换为泛型Task<TResult>。最新的结构速度更快,更方便,而且更复杂。 为了使用非泛型的任务类,调用Task.Factory.StartNew方法,将方法传进委托中。 Task.Factory.StartNew会返回一个Task对象,你可以使用它去监控这个task,比如,你可以调用它的wait方法等待它直到它完成。
当你调用task的Wait 方法时,一个未处理的异常会很容易地重新抛出到宿主线程上。(如果你不调用Wait方法而是放弃这个task,一个未处理的异常将会关闭掉这个进程) 泛型Task<Tresult>类是非泛型Task的子类。它让你从这个已经完成执行的task中得到一个返回值。在下面的例子中,我们使用Task<TResult>来下载一个web page
Task Parallel Library有许多的功能,特别是提升多核处理器的性能。我们会在并行编程中继续讨论TPL。 三、不用TPL进入到线程池如果你的应用程序是.NET Framework的早期版本(4.0之前的版本),你将不能使用TPL。你必须使用老的结构进入线程池: ThreadPool.QueueUserWorkItem和asynchoronous delegates.两者的不同点是asynchronous delegates让你从线程那里返回数据。Asynchronous delegates收集任何exception返回给调用者。 要使用QueueUserWorkItem,只需调用这个方法的运行在线程池上的委托。
我们的目标方法Go,必须接收一个简单object类型的参数(为了满足waitCallBack委托)。这将提供一个简单的方式传递数据到方法中,就像是ParameterizedThreadStart。不像Task,QueueUserWorkItem不会返回一个对象去帮助你之后管理执行。还有,你必须显式在目标方法的代码中写处理异常的代码-因为未处理的异常将会终止程序。 ThreadPool.QueueUserWorkItem没有提供从一个已经完成的线程中得到它的返回值的机制。Asynchronous delegate invocations(asynchronous delegates for short)解决了这个问题,允许任何个数类型化的参数在两个方向传递。此外,在asynchronous delegates上未处理的异常很方便地在原始线程上重新抛出(更准确地说,这个线程叫做EndInvoke),因此不需要显示处理。 下面是怎样通过一个asynchronous delegate开始一个worker task:
在下面的例子中,我们使用一个asynchronous delegate invocation运行一个与主线程同时运行的简单方法,这个方法返回一个字符串的长度:
EndInvoke做三件事情。第一,如果asynchronous delegate没有完成执行,则一直等待它完成。第二,接收返回值(以及任何ref或者out参数)。第三,返回任何未处理的线程异常给调用它的线程。 当你调用BeginInvoke方法时,可以指定一个call back delegate-一个可以接收一个IAsyncResult 对象的方法,它会在委托方法完成后被自动调用这个允许正在发动的线程忘记asynchronous delegate,但它在call back结束时需要一点额外的工作。 v写在最后
|
|