1

我正在编写一个类似于键值存储的系统,但不同的是,get 和 set 操作经常被调用。

在服务器端,我刚才使用了“每个客户端一个线程”的线程模型。但是在这个应用程序中,每个任务来自客户端的连接数约为一万,所以我使用的模型很慢。

在这种情况下我可以选择哪种线程模型?

谢谢

4

2 回答 2

2

您可能应该包括有关为什么您看到系统如此缓慢的其他详细信息。如果您使用互斥锁,您是如何设计它们的?互斥体是否保护整个键值存储或其子集。通常,将大表拆分为单独的小表(行)有助于使事情变得更加并行。此外,您是否遇到了线程等待另一个线程的问题。如果是这样,您可能最好使用条件变量。

于 2013-08-12T05:05:06.850 回答
1

实际上,“每个客户端一个线程”模型非常有效。在原始性能、延迟、系统调用数量方面,很难做得更好。但是,它的可扩展性不是很高,因为:

  • 每个线程都有自己的栈,所以内存/连接比很差
  • 操作系统调度开销随着线程数的增加而增加
  • 当大量线程在同一资源上阻塞时,并发管理原语(互斥锁、条件变量等)效率较低。

我认为选择一个好的线程模型的关键是评估你的操作的相对成本,以及它们是否可以阻塞。例如,协议编组/解组的成本是否高于访问内部数据结构的成本?数据访问能否生成阻塞磁盘 I/O?ETC ...

根据结果​​,您可以想象各种模型。

第一个可能的模型(memcached 模型):

  • 1个线程(事件循环)用于信号管理,TCP接受管理。每次接受新连接时,都会将其分派(通过循环)到连接管理线程之一

  • n 个线程用于连接管理。每个线程都是对其关联连接的偶数循环(e)轮询。任何传入的查询都由线程处理。对全局数据结构的任何访问都必须受到某种互斥机制的保护。

如果数据结构访问是快速且可预测的操作,则此模型可以正常工作。如果互斥太复杂,或者全局数据结构的争用太多,可以通过增加一个专门的线程来管理数据结构操作来改进这个模型。

  • 1个线程(事件循环)用于信号管理,TCP接受管理。
  • 用于连接管理的 n 个线程(事件循环)
  • 快速内存队列
  • 1个线程处理所有数据结构访问,监听快速内存队列

在这个模型中,连接线程对协议进行解码/编码(昂贵的操作),并通过将事件发布到内存队列来将所有数据访问委托给专用线程。一旦专用线程为连接线程发布结果,就会使用特定的文件描述符来唤醒事件循环。所有数据访问操作都是序列化的,不需要互斥锁来保护相关的数据结构。

以前的模型假设数据访问比协议管理本身便宜或便宜。如果这是错误的,那么以下模型可能更好:

  • 1个线程(事件循环)用于信号管理,TCP接受管理。
  • 用于连接管理的 n 个线程(事件循环)
  • 快速内存队列
  • m个线程用于数据/查询管理,监听内存队列

在此模型中,n 个连接线程仅处理协议编码/解码操作,并将其他所有内容委托给 m 个线程池。这些线程必须管理对全局数据结构的并发访问。最终,只要你有足够多的 I/O 或繁重的计算,它们就会阻塞。

还有许多其他可能的变化,这些只是主要思想。

于 2013-08-12T12:05:54.033 回答