过程比库更好的情况

最近,我与一位同事争论了如何通过引入第三方库作为该应用程序的依赖项来扩展关键应用程序的功能(由高度重要的功能组成)。

以下是向应用程序提供该功能的两种基本方法。

图1:作为库的能力与作为另一个过程的能力
  • 将功能添加为第三方库–在这种方法中,新功能被添加为程序的内部编译依赖项。
  • 将功能用作另一个过程–在这种方法中,新功能将不是内部编译依赖项。 它是单独编译的,将作为另一个进程运行。 新功能可以用作该特定过程公开的服务。

如果我们要将此功能添加为应用程序的主要功能或作为主要功能的扩展,我会同意我同事的建议。 但是,我们的情况如下。

  • 该应用程序的主要预期功能应该是经过良好测试的最少组件。
  • 新添加的功能经常更改。 因此,需要频繁部署。
  • 不能假定环境是同质的。

我同事的一个论据是, 引入另一个进程将给系统带来负担,因为即使我们不经常使用该进程,我们也需要为其分配资源。

但是,当使用库时,它将成为我们程序的内部编译依赖项,这通过引入更新的代码行而增加了另一种复杂性。

图2:地址空间正被第三方库和进程破坏
图3:运行时正被第三方库和进程崩溃

可能有人认为,只要我们能够正确处理使用该库的地方,第三方库就不会使应用程序崩溃。 但是,如果第三方库执行的操作会损坏进程 地址空间 ,则无法采取任何措施来防止它。 内存溢出,堆栈溢出和各种终止命令就是这种情况。

线程崩溃与进程崩溃

崩溃的进程不会导致其他进程崩溃,而崩溃的线程可能会对其他线程造成严重破坏。
并非所有线程异常都可以使用try-catch捕获。 线程除了引发异常外,还可以做更多的事情。 流氓线程可以通过错误的本机或ctypes代码在进程中的任何位置(包括python运行时本身)破坏内存结构,从而破坏整个进程。

图4:满足的依赖性与未满足的依赖性

当我们引入第三方库时,我们需要确保该库作为先决条件所期望的所有依赖项都应得到满足。 如果我们可以确认目标环境的同质性,那么这不是一个大问题。 如果环境是异构的,则代码库的编译将失败。

图5:将应用程序从语言A迁移到语言B

每当您需要对应用程序进行重大转换(即,将整个语言或其编写的版本切换)到应用程序时,都需要确保第3方库也已正确迁移。

图6:引入新版本

每次引入第3方库的新版本时,都需要再次部署整个程序以采用该新版本。 对于基本功能是另一回事的应用程序,这不是一个好条件。 为了修改上述基本功能以外的其他目的而重新编译程序可能会对应用程序造成额外的风险。

在Python中,由于GIL(全局解释器锁定),单个python进程无法并行运行线程(利用多个内核)。 但是,它可以同时运行它们(I / O绑定操作期间的上下文切换)