[英]Design multi-threaded chat server with low thread contention
我在考虑如何以某种方式使用 C++ 制作一个多线程聊天服务器,从而最大限度地减少线程争用。
在我的初始设计中,我在服务器中有一个 sockets 的std::vector
。 当客户端连接到服务器时,套接字被添加到 sockets 的这个向量中。
还有一个std::unordered_map<string, Socket*>
允许为用户名查找相应的套接字。 当客户端使用其用户名和密码登录时,我们向 hash map 添加一个条目。 当用户注销时,我们删除 hash map 中的相应条目。
客户端将发送以用户名为地址的消息。 当他们到达服务器时,我们使用 hash map 查找套接字,并通过该套接字发送消息。
由于服务器是多线程的,并且提到的数据结构可以从不同的线程读取/写入,我们现在需要使用一些线程同步机制来保护它们,例如互斥锁。 但我认为这样做会因为线程争用而降低性能。 基本上,所有线程都需要访问这些数据结构才能发送消息,但只有其中一个线程可以同时使用它们。 我认为使用这种方法的性能不会比使用单线程更好。
如何改进我的设计以获得更好的性能?
我认为使用这种方法的性能不会比使用单线程更好。
不必要。 由于您的 map 是指针的 map,而不是对象的 map数据结构。
但是,您需要确保安全处理 object 的生命周期。 这是std::shared_ptr<>
是您的朋友的情况之一,因为它保证了线程安全的所有权安全。
例如:
std::mutex table_mtx;
std::unordered_map<string, std::shared_ptr<Socket>> sockets;
void send(const std::string& msg, const std::string& dst_name) {
std::shared_ptr<Socket> dst;
{
std::lock_guard<std::mutex> lock(table_mtx);
// Increments the ref-count on the socket, so even if it's removed
// from the map, it won't be deleted until we are done with it.
dst = sockets.at(dst_name);
}
if(dst) {
dst->send(msg);
}
}
显然,当同时使用同一个套接字时, Socket
也需要有一个内部互斥体来处理争用。 但是,如果 user1 向 user2 发送消息,而 user3 向 user4 发送消息,则争用将仅限于 map 内的查找,而操作的 rest 将是并发的。
由于聊天具有高度的时间相关性(因为对话),逻辑答案是缓存结果。 您需要一个弱 ptr 来进行失效。
简单的解决方案是创建一个引用计数消息 class 并使用消息队列。 如果 Alice 想向 Bob 和 Charlie 发送消息,则创建引用计数消息 class 的实例,然后调用“队列消息”function 将同一消息的实例排队发送给 Bob 和 Charlie。
“队列消息”功能的工作原理如下:
您的服务器所做的大部分工作将完全不在此“队列消息” function 之外。 所有的发送、解析和接收都可以在没有任何锁的情况下进行。 当你收到一条消息时,你可以遵循同样的逻辑:
接收队列调度逻辑:
顺便说一句,我是 WebMaster 的 ConferenceRoom 软件的主要开发者。 所以我做了这个。 在十多年前的硬件上以这种方式处理一万个客户是没有问题的。 今天,我会使用 boost 为我完成大部分工作。
第一个简单的解决方案:
如果服务器上有足够的资源或客户端不多,我建议在这里避免大部分的多线程复杂性,并将所有发送或接收功能放在一个线程中(一个用于发送,另一个用于接收操作)。 因此,线程有它们的工作套接字,并且只保留发送和接收客户端队列的锁。 这些锁可以由生产者/消费者模式处理。
更高级但也更复杂的解决方案:您必须使用更优化的结构。 使用“unordered_map” object 会使您的套接字搜索机制非常低效。 此外,您不应该在需要锁的任何地方使用排他锁,也可以考虑在任何可能的地方使用非排他锁。
无论如何,最好利用现有的线程安全和无锁库。 你可以在网上找到很多。 我在 Google 上为您搜索一个:
https://github.com/khizmax/libcds
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.