有什么情况下最好使用一个普通的旧的Thread对象而不是一个新的构造?
我在博客文章中看到很多人,在这里SO或者避免或者build议不要使用最近版本的C#中的Thread
类(我的意思是当然是4.0+,加上Task
和朋友)。 甚至在之前,有一个争论是,在很多情况下, ThreadPool
类可以replace一个普通的旧线程的function。
此外,其他专门的机制进一步使Thread
类不那么吸引人,比如Timer
代替丑陋的Thread
+ Sleep
组合,而在GUI中我们有BackgroundWorker
等等。
尽pipe如此, Thread
对于一些人(包括我自己)来说似乎仍然是一个非常熟悉的概念,当面对涉及某种并行执行的任务时,直接跳转到使用旧的Thread
类。 我最近一直在想如果是时候修改我的方式了。
所以我的问题是,是否有任何情况下使用一个普通的旧的Thread
对象,而不是上述构造之一是必要的或有用的?
Thread类不能被废弃,因为它显然是你提到的所有其他模式的实现细节 。
但这不是你的问题。 你的问题是
有没有什么情况下,使用一个普通的旧的线程对象而不是上面的构造之一是必要的或有用的?
当然。 正是在这些情况下,其中一个较高层次的结构不能满足您的需求。
我的build议是,如果你发现自己现在的高抽象工具不能满足你的需求,而你希望用线程来实现一个解决scheme,那么你应该确定你真正需要的缺失的抽象,然后实现这个抽象使用线程 ,然后使用抽象 。
线程是某些事物(即并行和不同步)的基本构build块,因此不应该被带走。 但是 ,对于大多数人和大多数使用情况来说,您提到的更适合使用的东西,比如线程池(它们提供了一个并行处理许多小作业的好方法,而不会一次产生2000个线程重载机器), BackgroundWorker
(这封装有用的事件为一个短暂的工作)。
但仅仅是因为在很多情况下,这些更合适,因为它们避免了程序员不必要地重复发明轮子,犯了愚蠢的错误等等,这并不意味着Thread类已经过时了。 它仍然被上面提到的抽象使用,如果你需要对线程进行细粒度的控制,那么你仍然需要它,而不是被更多的特殊类所覆盖。
类似地, .NET
并不禁止使用数组,尽pipeList<T>
更适合人们使用数组的情况。 简单地说,因为你可能仍然想要构build标准lib所不包含的东西。
Task
和Thread
是不同的抽象。 如果你想build立一个线程的模型, Thread
类仍然是最合适的select。 例如,如果你需要与当前线程进行交互,我没有看到任何更好的types。
然而,正如你所指出的,在许多情况下,.NET已经添加了几个比Thread
更可取的专用抽象。
Thread
类不是过时的,在特殊情况下仍然有用。
在我工作的地方,我们编写了一个“后台处理器”作为内容pipe理系统的一部分:一个监视目录,电子邮件地址和RSS源的Windows服务,每当新的东西出现时,就执行一个任务 – 通常导入数据。
为此尝试使用线程池不起作用:它试图同时执行太多的东西,并垃圾的磁盘,所以我们直接使用Thread
类来实现我们自己的轮询和执行系统。
新的选项使得(昂贵的)线程的直接使用和pipe理更不频繁。
当遇到涉及某种并行执行的任务时,直接跳转到使用旧的Thread类。
这是一个非常昂贵和相对复杂的并行方式。
请注意,费用最重要的是:你不能用一个完整的线程做一个小的工作,这是适得其反的。 ThreadPool消除成本,Task类复杂性(exception,等待和取消)。
为了回答“ 有没有什么情况下使用一个普通的旧线程对象是必要的或有用的 ”,我会说一个普通的旧线程是有用的(但不是必须的),当你有一个长期的运行过程,从不同的线程进行交互。
例如,如果您正在编写订阅接收来自某种消息队列消息的应用程序,并且您的应用程序将不仅仅处理这些消息,那么使用一个Thread将是有用的,因为该线程将是自给自足的(即你没有等待它完成),而不是短暂的。 使用ThreadPool类更多的是排队一堆短命的工作项,并允许ThreadPool类有效地处理每一个新的线程可用。 任务可以用在你直接使用线程的地方,但在上面的场景中,我不认为他们会给你买太多的东西。 它们可以帮助你更容易地与线程交互(上面的场景并不需要这些线程),并且帮助你根据处理器的数量确定实际上应该使用多less个线程(这不是什么)你想要的,所以你会告诉任务,你的事情是LongRunning在当前4.0实现的情况下,它只会创build一个单独的非池线程)。
可能不是你期望的答案,但是我在使用.NET Micro Framework进行编码时总是使用Thread。 MF是相当的削减,不包括更高层次的抽象和Thread类是超级灵活的,当你需要从低MHz的CPU中获得性能的最后一点。
您可以将Thread类与ADO.NET进行比较。 这不是推荐工作的推荐工具,但也不是过时的。 其他工具build立在它之上,以减轻工作。
使用Thread类比其他东西没有错,特别是如果这些东西不提供您需要的function。
这不是绝对过时的。
multithreading应用程序的问题在于它们很难正确(往往是不确定的行为,input,输出以及内部状态都很重要),所以程序员应该尽可能地将大量的工作推到框架/工具上。 摘掉它。 但是,抽象的死敌是performance。
所以我的问题是,是否有任何情况下使用一个普通的旧的线程对象,而不是上述构造之一是必要的或有用的?
只有在出现严重的性能问题和高性能目标的情况下,才会使用线程和locking。
当我需要保持计数和控制我已经启动的线程时,我总是使用Thread类。 我意识到我可以使用线程池来保存我所有的优秀工作,但是我从来没有find一个好方法来跟踪当前正在进行的工作或状态。
相反,我创build了一个集合,然后把这些线程放在这些集合中,线程完成的最后一件事就是将它从集合中移除。 这样,我总是可以知道有多less个线程在运行,我可以使用这个集合来询问每个线程在做什么。 如果出现这种情况,我需要全部杀死它们,通常情况下,你必须在你的应用程序中设置某种“中止”标志,等待每一个线程自行注意到自我终止 – 就我而言,我可以走集合,并发出一个Thread.Abort到每个轮stream。
在这种情况下,我还没find直接使用Thread类的更好的方法。 正如Eric Lippert所说的,其他的只是更高层次的抽象,当可用的高层实现不能满足您的需求时,适合与更低层次的类进行合作。 正如你有时需要做Win32 API调用,当.NET不能满足你的确切需求时,总会有一些情况,尽pipe最近的“进步”,Thread类是最好的select。