多线程与多实例 - 选择哪个?

时间:2012-02-27 22:15:54

标签: c# .net multithreading

这两种情况之间是否会有很大差异:

  1. 一个应用程序实例创建100个线程来处理一些作业
  2. 同一个应用程序的10个实例分别创建10个线程来处理作业(总计100个)
  3. 两种情况下的线程数都是相同的。是一种表现还是对一种表现的任何改进?

      

    实例 - 例如控制台应用程序,所以在第二种情况下   将运行10个控制台应用程序。每个应用程序都有它   自己的文件夹。

5 个答案:

答案 0 :(得分:5)

线程使用的资源少于进程,因此理论上选项1将“更好”。但是,您可能不会注意到两者之间存在很大差异,因为100个单独的线程进程同时运行并且争取相同的O / S资源几乎可以保证您的系统停止运行

我会选择选项3 - 一个包含相当小的线程池的进程。这样,一些工作将同时执行,其余工作将排队等待轮到他们。如果要运行大量的工作,这种方法也可以很好地扩展。

请参阅ThreadPool类,或最好,这是其上面的许多更高级别的抽象之一(例如task library,甚至是普通的{{3} }})。

答案 1 :(得分:2)

选项2(至少)有以下开销:

  • 更多流程对象
  • 每个进程的静态内存更多
  • CLR和jitted代码的更多实例
  • 上下文切换需要切换地址空间(非常昂贵)
  • 分享应用程序数据结构的机会较少
  • 您需要跨进程通信。简单方法调用成为IPC操作
  • 为您完成更多工作
  • 更多错误机会(IPC通讯,叉炸弹......)
  • 更糟糕的可调试性
  • 没有通过线程池的内置负载平衡
  • 更难和更容易出错的同步。
  • 更少内置内容和更慢

如果可以选择(1),为什么选择(2)?有正当理由,但这些原因相当特殊:

  • 您需要能够容忍任意内存损坏。这种情况不正常(完全没有!)
  • 你需要杀死线程的能力。对于单线程,这在CLR内部无法可靠地完成。但你可以合作完成,这通常是更好的选择
  • 您的线程需要在不同的用户等下运行。这几乎不会发生。

一般来说,处理越少越好。

答案 2 :(得分:2)

这取决于您正在做什么,但在大多数情况下,选项1将具有最佳性能并且将是最容易使用的。
为了给你一个更完整的答案,我需要知道以下内容:

  • 100个主题是否都执行相同的任务?
  • 100个主题是否访问相同的数据?
  • 线程处理的任务是否具有自然停机时间(等待另一个进程完成或资源可用)?
  • 线程处理的任务是否都试图访问有限的资源(如硬盘或网卡)?
  • 您的计算机可以同时处理多少个并发线程(例如,具有超线程的4核处理器可以处理8个线程,没有超线程的4核处理器可以处理4个线程)?
  • 如果线程出现问题,会发生什么?进程是否崩溃,是否重新启动了线程?

如果线程都执行相同的任务,将它们保持在一起将使最终用户和后来的开发人员更容易,因为所有内容都在一个地方。

如果线程都访问相同的数据,那么将它们保持在同一个进程中将允许您在线程之间共享该数据(虽然在更改数据时注意竞争条件)并减少内存占用量。您也可以组合线程来访问来自相同块的数据,因此可以将所有内容缓存在CPU上,从而减少内存延迟的影响,但这不是我建议的尝试。

由于许多答案都提供了有关如何实现项目的建议,因此了解每个线程是否设计为在其运行的所有时间内完全使用CPU,或者这些是后台任务,在执行之前执行少量工作回到睡眠状态将有助于我们根据您的情况提出建议。

了解正在运行的硬件将帮助我们提供适合您情况的建议。

如果线程失败,会发生什么?如果一个线程每天失败一次,用户是否需要进行干预,停止该过程并重新启动它?如果是这样,那么在其他线程上完成的任何未保存的工作都将丢失。在这种情况下,让每个线程在自己的进程中运行将使您只能丢失失败的进程。


Christian Hayter的选择3是有道理的,但并不总是与C#相关 如果您查看documentation,请说明:

  

操作系统ThreadId与托管线程没有固定的关系,因为非托管主机可以控制托管和非托管线程之间的关系。具体来说,复杂的主机可以使用CLR Hosting API针对同一操作系统线程调度许多托管线程,或者在不同操作系统线程之间移动托管线程。

基本上这意味着.Net框架会将你的线程集中在一起,如果感觉它是个好主意的话。如果您的进程使用更多线程,则更有可能发生这种情况,而多线程进程之间的总线程数可能保持非常相似。因此,我希望1个进程,100个线程解决方案使用更少的总线程然后10个进程,每个10个线程(类似10到40,但你必须检查)。

话虽如此,框架将是猜测,所以在某些情况下,线程池将是更好的选择。请务必先阅读documentation,因为在某些情况下不应使用线程池。有关池的快速教程可以在MSDN找到。还有一个thread讨论何时使用线程池。


如果您提供更多信息,我会尝试提供更准确的答案。否则,在大多数情况下,选项1(可能还有选项3)是更好的选择。

答案 3 :(得分:1)

是的,这将是一个很大的不同。每种方法都有利弊:

  • 内存消耗。显然,10个过程中的每一个都需要 创建自己的地址空间等。
  • 简单的通信/同步。虽然它相对容易 沟通/同步线程(您可以使用关键部分,其中 是最有效的方法之一,它之间会更难 流程。在您的方案中,您将拥有10个进程和10个线程 必须做两种方式。
  • 崩溃。如果其中一个线程正在执行 有些不对劲,整个过程都会消失。

我个人更喜欢一个进程/多个线程。但是,这实际上取决于任务。

答案 4 :(得分:0)

这么奇怪的问题,很难找到实际的应用。但我认为从性能的角度来看,选项1会更好。通过运行同一个应用程序的10个实例,可能会有更多工作要做。 (清理,注册,控制台打开等)

编辑* 因为使用选项1,您可以排队工作并让线程处理负载。