多线程与多实例化-选择哪一种

本文关键字:选择 哪一种 实例化 多线程 | 更新日期: 2023-09-27 18:26:08

这两种场景之间会有很大区别吗:

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

在这两种情况下,线程的数量将是相同的。是某种性能还是某种类型的改进?

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

多线程与多实例化-选择哪一种

线程使用的资源比进程少,因此理论上选项1会"更好"。然而,您可能不会注意到两者之间有多大区别,因为100个独立的线程都同时运行,争夺相同的O/S资源几乎可以保证会让您的系统陷入停顿。

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

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

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

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

如果你可以选择(1),你为什么要选择(2)?有一些合理的理由,但这些理由相当特殊:

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

一般来说,流程越少越好

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

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

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

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

由于许多答案都是关于如何实现您的项目的建议,了解每个线程是否设计为在运行时始终充分使用CPU,或者这些是在返回睡眠前做少量工作的后台任务,将有助于我们根据您的情况提出正确的建议。

了解流程将在什么硬件上运行将有助于我们为您的情况提供正确的建议。

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


Christian Hayter的选项3是有道理的,但并不总是与C#相关
如果你看一下文件,它会说:

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

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

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


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

是的,这将是一个很大的区别。每种方法都有优缺点:

  • 内存消耗。显然,10个过程中的每一个都需要创建自己的地址空间等
  • 通信/同步的简单性。虽然相对容易通信/同步线程(可以使用关键部分是最有效的方法之一),在过程。在有10个进程和10个线程的场景中必须双管齐下
  • 崩溃。如果进程中的某个线程出了什么问题,整个过程就完了

我个人更喜欢一个进程/多个线程。然而,这确实取决于任务。

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

编辑*因为有了选项1,您就可以用螺纹来处理工作,让螺纹来处理负载。