没有线程的并发

Concurrency without threads

我有这个单一的整体守护程序,它执行多项操作,例如与北向 API 接口、与南向 API 接口、执行状态机、构建内部数据库。

目前,我遇到了可伸缩性问题,我想重新设计守护进程,以便守护进程中的所有多个操作都是并发的。但是使用线程会使逻辑复杂化,因为我最终不得不:

所以我的问题是请提出一种设计方法,我仍然可以使操作并发并消除线程的复杂性。

我的应用程序目前使用 C 语言。任何示例开源 (FOSS) 项目都可以帮助我理解设计方法。

您剩下的唯一选择是:

  • 多进程方法(即:spawn()fork()exec() 等。您仍然需要同步数据、设置共享内存等。线程可能会更容易).
  • 硬着头皮在没有并发的情况下生活。
  • 精通"lock free / lockless programming" approaches,这仍然可能至少需要原子操作。

软件同步、保护和 future-proofing/scalability 是任何执行重要操作的生产代码中的常见问题。试图完全避免它们通常表明您比避免线程模型更担心。

这听起来像是一个完美的 go 案例,它提供了一个基于 Hoare 的通信顺序进程 (CSP)* 的并发模型。幸运的是,您不必使用 go 来获取 CSP。 ZeroMQ fame 的 Martin Sustrik 给了我们 libmill,它提供了 C 中的 go 并发原语。不过,您可能会考虑 go 的其他功能。

* 与其尝试直接描述 CSP,我建议您观看 Rob Pike 的一些优秀视频,例如:Go Concurrency Patterns.

无需 运行 多个线程即可实现异步执行的一种方法是使用命令模式和命令队列。您可以使用任何编程语言来实现它。当然事情不会真正并行执行,但这是在资源非常有限的环境中进行异步编程的方式。 Robect C Martin 在他的 video.

中对此进行了很好的描述

示例场景:

  • 您将初始命令添加到队列中(为了举例,它只是一个简单的命令)。
  • 你开始无限循环,它只做一件事:
    1. 从队列中取出下一个命令
    2. 在当前线程上执行获取的命令
  • 我们的命令(我们称它为 CheckButtonPressed)可以做一些简单的检查(例如,是否单击了按钮或某些 Web 服务响应了一些值)
    • 如果条件检查是否定的,命令会将自己添加回队列(队列永远不会为空,我们一直在检查按钮是否被按下)
    • 如果条件检查是肯定的,我们将 HandleButtonClick 命令添加到队列中,其中包含我们想要 运行 响应此事件的任何代码。
  • HandleButtonClick 命令被处理时,它将执行任何需要的代码,最后它会再次将 CheckButtonPressed 添加到队列中,以便可以再次按下按钮并且队列永远不会为空.

如您所见,除了初始命令(在开始队列处理循环之前添加到队列中的命令)之外,所有其他命令都由其他命令添加到队列中。命令可以是有状态的,但不需要线程同步,因为只有一个线程。