1

自从我发现套接字以来,我一直在使用非阻塞变体,因为我不想费心学习线程。从那以后,我在线程方面积累了更多经验,我开始问自己......你为什么要把它用于套接字?

线程的一个大前提似乎是它们只有在处理自己的数据集时才有意义。一旦您有两个线程处理同一组数据,您将遇到以下情况:

if(!hashmap.hasKey("bar"))
{
  dostuff               // <-- meanwhile another thread inserts "bar" into hashmap
  hashmap[bar] = "foo"; // <-- our premise that the key didn't exist
                        //     (likely to avoid overwriting something) is now invalid
}

现在想象一下 hashmap 将远程 IP 映射到密码。你可以看到我要去哪里。我的意思是,当然,这种线程交互出错的可能性很小,但它仍然存在,为了保证程序的安全,你必须考虑每一种可能性。与简单的单线程工作流相比,这将显着增加设计工作量。

我可以完全看到线程对于处理单独的数据集或对于显式优化以使用线程的程序是多么的好。但是对于“一般”情况,程序员只关心发送一个工作和安全的程序,我找不到任何理由使用线程而不是轮询。

但是看到“单独的线程”方法非常普遍,也许我忽略了一些东西。开导我!:)

4

2 回答 2

4

使用带有套接字的线程有两个常见的原因,一个好一个不太好:

很好的理由:因为您的计算机有多个 CPU 内核,并且您想利用额外的内核。单线程程序只能使用一个核心,因此在繁重的工作负载下,您会将一个核心固定在 100%,而其他核心则闲置并浪费掉。

不太好的原因:您想使用阻塞 I/O 来简化程序的逻辑——特别是,您希望避免处理部分读取和部分写入,并将每个套接字的上下文/状态保留在它关联的线程。但是您还希望能够一次处理多个客户端,而不会导致慢速客户端 A 导致 I/O 调用阻塞并推迟对快速客户端 B 的处理。

第二个原因不太好的原因是,虽然每个套接字有一个线程似乎简化了程序的设计,但实际上它通常会使它复杂化。它引入了竞争条件和死锁的可能性,并使得难以安全地访问共享数据(如您所述)。更糟糕的是,如果您坚持阻塞 I/O,则很难干净地关闭程序(或以任何其他方式从线程套接字以外的任何地方影响线程的行为),因为线程通常在 I/O 中被阻塞O 呼叫(可能无限期地)没有可靠的方法来唤醒它。(信号在多线程程序中不能可靠地工作,回到非阻塞 I/O 意味着您失去了您希望的简化程序结构)

简而言之,我同意 cib - 多线程服务器可能会出现问题,因此通常应该避免使用,除非您绝对需要使用多个内核 - 即使那样,为了安全起见,使用多进程而不是多线程可能会更好清酒。

于 2012-06-27T23:55:43.627 回答
2

线程最大的好处是可以防止处理请求时累积的延迟时间。轮询时,您使用循环来为每个套接字提供状态更改服务。对于少数客户来说,这不是很明显,但是在与大量客户打交道时可能会导致严重延误。

假设每个事务都需要一些预处理和后处理(取决于协议,这可能是微不足道的处理量,或者可能像 BEEP 或 SOAP 那样相对重要)。预处理/后处理请求的总时间可能会导致待处理请求的积压。

出于说明目的,假设请求的预处理、处理和后处理阶段各消耗 1 微秒,因此完成总请求需要 3 微秒。在单线程环境中,如果传入的请求超过每秒 334 个请求(因为在 1 秒的时间内处理所有收到的请求需要 1.002 秒),系统将不堪重负,导致每秒 0.002 秒的时间不足。但是,如果系统使用线程,那么理论上可能只需要 0.336 秒 *(共享数据访问 0.334 + 0.001 预处理 + 0.001 后处理)的处理时间来完成在 1 秒内收到的所有请求时间段。

虽然理论上可以在 0.336 秒内处理所有请求,但这将要求每个请求都有自己的线程。更合理的做法是将组合的前/后处理时间(0.668 秒)乘以请求数并除以配置的线程数。例如,使用相同的 334 个传入请求和处理时间,理论上 2 个线程将在 0.668 秒内完成所有请求(0.668 / 2 + 0.334),4 个线程在 0.501 秒内完成,8 个线程在 0.418 秒内完成。

如果您的守护程序接收的最高请求量相对较低,那么具有非阻塞 I/O 的单线程实现就足够了,但是如果您预计偶尔会出现大量请求,那么值得考虑使用多线程模型。

我已经编写了多个吞吐量相对较低的 UNIX 守护程序,并且为了简单起见,我使用了单线程。但是,当我为 ISP 编写自定义 netflow 接收器时,我为守护进程使用了​​线程模型,它能够处理 Internet 使用的高峰时间,而系统负载平均波动最小。

于 2012-06-27T23:58:47.583 回答