环境:Ubuntu 16.04 - Linux,使用GCC编译C ++ 11。软件并不需要跨平台 - 但在其任务中是高效的,并且是一个优秀的守护进程。
我目前有一个简单的应用程序,它基本上充当第三方服务和websocket连接之间的中介。所以用户通过websocket连接我的服务与所述第三方服务交谈。
| End-User | <-C1-> | My Application | <-C2-> | 3rd Party Service |
我的应用程序目前有两个主线程:
线程1 - 收听websocket连接,每当收到消息时,它会将包含该消息的对象和请求所述消息的websocket连接推送到fifo任务队列。
线程2 - 循环显示消息队列,然后弹出消息并对其进行处理
问题是线程1非常快,并且可以轻松处理100多个websocket连接。线程2有时阻塞任务并且可能很慢,因为所述第三方服务的某些队列项处理需要一段时间。这意味着如果用户A确实请求1(需要5秒钟响应),而后来发出请求2的用户B则必须等待用户A的请求1完成,即使请求2需要不到1毫秒。
我建议的解决办法是:
线程1可以轻松处理100个websocket连接,每个连接可以在1分钟到1分钟之间完成任务请求。所有线程3 - 100都在睡觉。这么多线程的原因是因为如果有50-60个连接都会产生不同的长时间运行请求,那么这些耗时的调用中的每一个只会阻塞一个线程,其他线程仍可以自由地在队列上工作,并且做其他任务。
我知道切换线程是一个密集型操作,但我不知道除了mulithreading之外的任何其他方法。
我用单个线程解决了同样的问题 - 但问题是服务器在等待第三方服务时阻止处理任何websocket消息。所以我把它碰到了两个线程 - 一个用于websocket,另一个用于处理任务队列。但现在问题是任务队列上的单个工作人员很慢,因为它正在顺序处理阻塞IO操作。
这听起来像是一个糟糕的设计理念吗?关于最佳实践的任何想法?
答案 0 :(得分:6)
是否存在太多线程?
是
100个帖子
如果在任何桌面/服务器上有点不理想,应该没问题。我有一台笔记本电脑在一个过程中约2000个线程后拒绝继续。
其他策略
对于maxiumum吞吐量,一个常见的设计决策是每个cpu内核约1个线程,并采用基于异步电路的设计。
一些例子:
libuv
升压:: ASIO
libdispatch
win32异步操作
答案 1 :(得分:3)
“有太多线程吗?” - 是的线程消耗您可能耗尽的系统资源。线程需要安排;需要内核的工作以及CPU上的时间(即使他们希望什么都不做)。更多线程增加了复杂性,使您的程序更难以推理并且更难调试。
确实存在太多线程的事情 - 永远不会创建超出您需要/对您的程序有意义的内容。
答案 2 :(得分:0)
最简单,也可能是最有效的方法是使用线程池。线程池通常由OS(或诸如.NET之类的基础平台)实现,并针对最佳吞吐量进行了优化。线程池连续监视发送到线程池的任务的执行效率,并在吞吐量下降时动态创建新线程,或者在一段时间内不执行时释放线程。创建和释放线程的算法非常复杂,在大多数情况下,线程池是将工作负载拆分为多个线程的最有效方法。
Windows和Linux都支持线程池,但是由于您使用的是C ++ 11,因此您还可以使用标准的C ++库线程池,可以通过调用函数std::async
来使用该线程池。这是一些不错的sample。