多线程或多进程

8
我正在为Linux设计一个专用的syslog处理守护进程,需要具有强大和可伸缩性,我正在考虑多线程与多进程之间的区别。
明显的多线程反对意见是复杂性和令人讨厌的错误。多进程可能会影响性能,因为IPC通信和上下文切换。
"Unix编程艺术" 这里 讨论了这个问题。
你会推荐基于进程的系统(如Apache)还是多线程方法?

我不确定您提供的关于您的目标/要求的信息是否足够,以便对此发表意见。 - Tall Jeff
Apache不一定是多线程或多进程的。您可以编译它,使其使用这些模型中的任何一个。它甚至可以在这两者之间都不工作。虽然我没有看到它以异步模式编译使用,但它也可以以这种方式工作。 - Vasil
8个回答

24

两者都有各自的复杂和复杂之处。

你可以选择其中任意一种。从宏观上讲,选择哪种可能并不重要。重要的是你做得有多好。因此:

做你最有经验的事情。 或者如果你领导一个团队,就做团队最有经验的事情。

--- 线程!---

我做了很多线程编程,我喜欢其中的某些部分,但也有一些部分我不喜欢。我学到了很多东西,现在通常可以写一个多线程应用程序而不会太痛苦,但它必须以非常特定的方式编写。即:

1)必须使用非常清晰定义的数据边界来编写,这些数据边界是100%线程安全的。否则,任何可能发生的情况都会发生,并且可能不是当您拥有调试器时...而且调试线程代码就像窥视Schrödinger的盒子...通过看进去,其他线程可能已经处理更多的内容。

2)必须编写压力测试机器的测试代码。许多多线程系统只在机器受到重压时显示其错误。

3)必须有一些非常聪明的人拥有数据交换代码。如果有任何捷径可以走,某些开发人员可能会走这条路,您将遇到一个错误的bug。

4)必须有抓住所有情况并以最小的麻烦重置应用程序的情况。这是因为生产代码会因为某些线程问题而失败。简而言之:show must go on。

---跨进程!---

我对基于进程的线程编程经验较少,但最近在Windows中进行了一些跨进程操作(其中IPC是Web服务调用...WOO!),这相对干净且简单,但我也遵循一些规则。总的来说,进程间通信会更加容错,因为程序非常好地接收来自外部世界的输入..而且这些传输机制通常是异步的。无论如何...

1) 定义清晰的流程边界和通信机制。使用TCP、Web服务、管道等消息/事件传递方式都可以,只要边界清晰,并且在这些边界上有大量的验证和错误检查代码。

2) 准备好应对瓶颈。代码容错性非常重要。我的意思是,有时候您可能无法写入那个管道。您必须能够重新排队并尝试再次发送消息,而不会导致应用程序锁定/抛出异常。

3) 一般情况下需要编写更多的代码,因为跨进程边界传输数据意味着您必须以某种方式对其进行序列化。这可能成为问题的源头,特别是当您开始维护和更改该代码时。

希望这能帮到您。


谢谢!在开发线程安全代码时要记住的好点。 - Santosh

3
您漏掉了太多细节。实际上,就您已经提出的内容而言,选择无关紧要,并且多线程并非比多进程本质上更容易出现错误;您忽略了这些技术为什么会有这样的声誉。如果您没有共享数据,那么问题不大(当然,可能还有其他问题,但我们需要详细信息才能决定)。此外,平台也很重要,在类UNIX操作系统上,进程本来就很轻量级。

然而,还有其他问题需要考虑。您将在什么样的系统上运行?如果您在单处理器系统上产生几个进程,则根据您可以指定的某些其他细节,您肯定不会获得太多好处。如果您描述一下您要解决的问题的性质,我们可以提供更进一步的帮助。


2

取决于您想使用哪种编程语言(以及哪些库)。

个人而言,我会选择多线程,因为我知道与线程相关的问题(以及如何解决它们)。

如果您想在多台计算机上运行守护程序并将负载分配给它们,则多处理可能会有所帮助,但我认为这不是一个主要问题。


2
如果想要更强壮的系统,使用多进程。
进程之间会共享日志负载。在某个时刻,一个记录日志的请求可能会遇到错误而导致记录器崩溃。使用多进程,只会失去一个进程及其对应的记录日志请求(由于错误无法处理)。
多线程容易出现崩溃,因为一个致命错误会导致整个进程崩溃。
多进程在某些方面更加具有挑战性,因为需要平衡进程之间的工作负载,这可能需要使用共享内存。

1
你需要在更新频繁且IPC成本过高的实例之间共享更新数据吗?如果是这样,多线程可能更好。否则,您必须权衡单独进程的健壮性和线程创建/通信的易用性哪个更重要。

0

好的,最终我们实现了一个多进程系统,使用管道进行进程间通信,并且有一个记录器按需生成进程。类似于 Apache httpd。它完美地工作。


0

感谢大家的反馈。

我决定采用类似于Apache Web服务器的多进程架构。 这些进程将在多处理器/核心系统上良好地扩展。 通信将使用管道或套接字进行。

进程将准备好在进程池中使用,因此没有进程生成成本。

与我所获得的健壮性相比,性能损失将是微不足道的。


0
一个问题是是否有必要做任何一种。我不知道你的需求细节,但使用select(2)的单线程应用程序可能适合你的需求,并且不具有进程或线程的缺点。这需要您能够将所有I/O集中到一个中心位置,最有可能通过回调分派到其他模块,但除非您有很多想要进行自己的I/O并且无法以这种方式重组的库,否则这并不难。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接