gpt4 book ai didi

c++ - 如何为 C++ 多线程应用程序选择正确的线程数?

转载 作者:IT王子 更新时间:2023-10-29 01:18:44 27 4
gpt4 key购买 nike

我是 C++ 后端开发人员。我为实时游戏开发服务器端。因此,应用程序架构如下所示:

1) 我有一个客户端类,它处理来自游戏客户端的请求。请求示例:登录、在商店(游戏内部商店)购买东西或制作东西。此客户端还处理来自游戏客户端的用户输入事件(通常是事件,当玩家玩游戏时,它每秒从游戏客户端发送十次到服务器)。

2) 我有线程池。当游戏客户端连接到服务器时,我创建客户端实例并将它们绑定(bind)到池中的线程之一。所以,我们有一对多的关系:一个线程 - 许多客户。循环法用于选择线程进行绑定(bind)。

3) 我使用 Libev 来管理服务器内的所有事件。这意味着当客户端实例通过网络从游戏客户端接收到一些数据,或者处理一些请求,或者试图通过网络向游戏客户端发送一些数据时,他会锁定他的线程。当他制作一些东西时,共享相同线程的其他客户端将被锁定。

所以,线程池是应用的瓶颈。为了增加服务器上的并发玩家数量,他们可以无延迟地玩游戏,我需要增加线程池中的线程数量。

现在应用程序在具有 24 个逻辑 cpu 的服务器上工作(cat/proc/cpuinfo 这么说)。我将线程池大小设置为 24(1 个处理器 - 1 个线程)。这意味着,对于当前在线的 2000 名玩家,每个线程为大约 84 个客户端实例提供服务。 top 表示处理器使用了不到 10%。

现在提问。如果我增加线程池中的线程数,它会增加还是减少服务器性能(上下文切换开销与每个线程的锁定客户端)?

UPD1) 服务器有异步 IO (libev + epoll),所以当我说客户端在发送和接收数据时锁定时我的意思是应对缓冲区。2)服务器也有后台线程用于慢任务:数据库操作,硬计算操作,......

最佳答案

很少有问题。

2) I have thread pool. When game client connect to server I create Client instance and bind them to one of threads from pool. So, we have relationships one to many: one thread - many Clients. Round-robin used to chose thread for binding.

你在任何一点上都没有提到异步 IO,我相信你真正的瓶颈不是线程数,而是线程因为 IO 操作而被阻塞的事实。通过使用异步 IO(不是另一个线程上的 IO 操作)- 服务器的吞吐量增加了巨大的数量级。

3) I use Libev to manage all events inside server. It's mean when Client instance receive some data from game client through network, or handle some request, or trying to send some data through network to game client he lock hi's thread. While he make some stuff other Clients, which share same thread will be locked.

同样,如果没有异步 IO,这个架构非常像 90 年代的服务器端架构(a-la Apache 风格)。为了获得最佳性能,您的线程应该只执行 CPU 绑定(bind)任务,而不应该等待任何 IO 操作。

So, thread pool is bottleneck for application. To increase number concurrent players on server, who will play without lags I need increase number of threads in thread pool.

大错特错。阅读有关 10k 并发问题的信息。

Now question. If I increase number of threads in thread pool is It increase or decrease server performance (Context switching overhead vs locked Clients per thread)?

因此,关于线程数作为核心数的轶事仅在您的线程执行 cpu 绑定(bind)任务并且它们永远不会被阻塞并且它们 100% 饱和 cpu 任务时才有效。如果您的线程也被锁或 IO 操作阻塞,那么这个事实就不成立了。

如果我们看一下常见的服务器端架构,我们可以确定我们需要的最佳设计

Apache 风格架构:
有一个固定大小的线程池。为连接队列中的每个连接分配一个线程。非异步IO。
优点: 非。
缺点:吞吐量极差

NGNix/Node.js 架构:
具有单线程 - 多处理应用程序。使用异步 IO。
优点:简单的架构,消除了多线程问题。与提供静态数据的服务器配合得非常好。
缺点:如果进程必须共享数据,大量的 CPU 时间会消耗在进程之间的序列化-传递-反序列化数据上。此外,如果处理得当,多线程应用程序可以提高性能。

现代 .Net 架构:
具有多线程单声道处理的应用程序。使用异步 IO。
优点:如果操作正确,性能会非常出色!
缺点:调整多线程应用程序并在不损坏共享数据的情况下使用它有点棘手。

总而言之,我认为在您的特定情况下,您应该明确地仅使用异步 IO + 拥有一个线程数等于内核数的线程池。

如果您使用的是 Linux,Facebook 的 Proxygen可以为您管理我们讨论的所有内容(具有异步 IO 的多线程代码)。嘿,Facebook 正在使用它!

关于c++ - 如何为 C++ 多线程应用程序选择正确的线程数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36735272/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com