我可以选择哪种线程模型?

时间:2013-08-12 03:43:58

标签: multithreading redis pthreads memcached threadpool

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

在服务器端,我现在使用'每个客户端一个线程'线程模型。但是在这个应用程序中,每个任务的客户端连接大约有一万个,所以我使用的模型很慢。

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

谢谢

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

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

  • 每个线程都有自己的堆栈,因此内存/连接比率不好
  • OS调度开销随着线程数的增加而增加
  • 并发管理原语(互斥,条件变量等)在同一资源上阻塞大量线程时效率较低。

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

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

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

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

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

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

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

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

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

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

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

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