multithreading与多实例 – 选择哪个?

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

  1. 一个应用程序实例创建100个线程来处理一些作业
  2. 同一个应用程序的10个实例分别创建10个线程来处理作业(总计100个)

两种情况下的线程数都是相同的。 是一种表现还是一种改进?

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

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

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

请参阅ThreadPool类, 或者最好是其上的许多更高级抽象之一(例如, 任务库 ,甚至是普通的旧异步委托 )。

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

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

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

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

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

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

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


Christian Hayter的选择3是有道理的,但并不总是与C#相关。
如果你查看文档 ,它会说:

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

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

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


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

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

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

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

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

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

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

  • 内存消耗。 显然,10个进程中的每个进程都需要创建自己的地址空间等。
  • 通信/同步的简单性。 虽然通信/同步线程相对容易(您可以使用关键部分,这是最有效的方法之一),但在进程之间进行操作会更加困难。 在具有10个进程和10个线程的场景中,您必须同时执行两种方式。
  • 崩溃。 如果进程中的一个线程出错了,整个过程就会消失。

我个人更喜欢一个进程/多个线程。 但是,它真的取决于任务。

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

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