是否有任何情况下,最好使用普通的旧Thread对象而不是其中一个较新的构造?

Tud*_*dor 111 .net c# multithreading

我在博客文章中看到很多人,在这里要么避免或建议Thread在最近版本的C#中使用该类(我的意思当然是4.0+,添加了Task&friends).甚至在此之前,关于这样一个事实的辩论:在很多情况下,ThreadPool类可以替换普通旧线程的功能.

此外,其他专门机制进一步使Thread类不那么吸引人,例如Timers替换丑陋的Thread+ Sleep组合,而对于我们有的GUI BackgroundWorker等.

不过,Thread似乎仍然对一些人(包括我自己),人的是,当涉及某种并行执行的任务面前,直接跳转到使用好老的一个非常熟悉的概念Thread类.我最近一直想知道是否该修改我的方式.

所以我的问题是,在使用普通旧Thread对象而不是上述结构之一时,是否有必要或有用?

Eri*_*ert 107

Thread类不能过时,因为它显然是你提到的所有其他模式的实现细节.

但那不是你的问题; 你的问题是

有什么情况下使用普通的旧Thread对象而不是上述结构之一是必要的还是有用的?

当然.正是在那些较高级别的结构之一不能满足您的需求的情况下.

我的建议是,如果您发现自己处于现有的更高抽象工具无法满足您的需求,并且您希望使用线程实现解决方案的情况下,那么您应该确定您真正需要的缺失抽象,然后实现该抽象使用线程,然后使用抽象.

  • 所有好建议.但是你有一个例子,其中一个普通的旧线程对象可能比其中一个较新的构造更可取吗? (33认同)
  • @RobertHarvey:当然.例如,如果您有一个经典的"生产者/消费者"情况,您希望有一个专门用于从工作队列中取出东西的线程和另一个专门用于将内容放入工作队列的线程.两者都永远循环; 他们没有很好地映射到你做了一段时间的任务,然后得到一个结果.您不需要线程池,因为只有两个线程.而且你可以聪明地使用锁和信号来确保队列保持安全,而不会长时间阻塞其他线程. (15认同)

Joe*_*oey 52

线程是某些事物的基本构建块(即并行性和异步性),因此不应该被带走.但是,对于大多数人和大多数用例,你提到的更合适的东西,比如线程池(它提供了一种很好的方法来并行处理许多小作业,而不会通过一次产生2000个线程来重载机器),BackgroundWorker(它封装了一个短期工作的有用事件.

但是,仅仅因为在许多情况下这些更合适,因为它们可以防止程序员不必要地重新发明轮子,做出愚蠢的错误等,这并不意味着Thread类已经过时了.它仍然被上面提到的抽象使用,如果您需要对更多特殊类未涵盖的线程进行细粒度控制,您仍然需要它.

同样,.NET不要禁止使用数组,尽管List<T>它更适合人们使用数组的许多情况.仅仅因为您可能仍希望构建标准库未涵盖的内容.

  • 仅仅因为自动变速器在99%的时间内工作,并不意味着手动变速器没有价值,甚至无视驾驶员的偏好. (6认同)
  • 由于我是骑自行车者和公共交通用户,因此不熟悉驾驶习语.但是手动变速器不是自动变速器的核心 - 它不是机械手移动操纵杆.就我所见,这并不是对另一方的抽象. (4认同)
  • 如果你们真的想要使用变速器比喻,大多数顺序变速器(例如宝马的SMG变速器)*实际上是带有计算机操作离合器和档位选择器的手动变速器.它们不像传统的自动变速器那样是行星齿轮系统. (3认同)
  • 您可以在第二段中将"thread"替换为"unmanaged code",它仍将为true (2认同)

Bri*_*sen 13

Task并且Thread是不同的抽象.如果要对线程建模,则Thread该类仍然是最合适的选择.例如,如果您需要与当前线程进行交互,我没有看到任何更好的类型.

但是,正如您所指出的,.NET已经添加了几个专用的抽象,Thread在许多情况下这些抽象都是优选的.


MiM*_*iMo 9

Thread班是不是过时了,它仍然是在特殊情况下非常有用.

在我工作的地方,我们编写了一个"后台处理器"作为内容管理系统的一部分:监视目录,电子邮件地址和RSS源的Windows服务,以及每次出现新事物时执行任务 - 通常是导入数据.

尝试使用线程池不起作用:它尝试同时执行太多的东西并丢弃磁盘,因此我们直接使用Thread类实现了自己的轮询和执行系统.


Hen*_*man 6

新选项使(昂贵的)线程的直接使用和管理不那么频繁.

人们在遇到涉及某种并行执行的任务时,直接跳转到使用好的旧Thread类.

这是一种非常昂贵且相对复杂的并行方式.

请注意,费用最重要:您不能使用完整的线程来完成一项小工作,这会适得其反.ThreadPool可以控制成本,Task类可以解决复杂性(例外,等待和取消).


Der*_*eer 5

要回答" 在使用普通的旧Thread对象时是否有必要或有用的任何情况 "的问题,我会说当你有一个漫长的运行过程时,一个普通的旧线程是有用的(但不是必需的)从不同的线程进行交互.

例如,如果您正在编写一个订阅从某种消息队列接收消息的应用程序,并且您的应用程序将不仅仅处理这些消息,那么使用Thread会很有用,因为该线程将是自足(即你没有等待它完成),它并不是短暂的.使用ThreadPool类更多的是排队一堆短期工作项,并允许ThreadPool类在新线程可用时有效地管理每一个.可以在你直接使用Thread的地方使用任务,但在上面的场景中,我认为他们不会给你买太多东西.它们可以帮助您更轻松地与线程交互(上面的场景不需要),并且它们有助于根据您拥有的处理器数量确定实际应该为给定的任务集使用多少线程(这不是什么你想要,所以你告诉任务你的东西是LongRunning,在这种情况下,在当前的4.0实现中它只会创建一个单独的非池化线程).