多线程游戏服务器的基本设计?

Posted

技术标签:

【中文标题】多线程游戏服务器的基本设计?【英文标题】:Basic design of a multithreaded game server? 【发布时间】:2010-09-30 20:22:03 【问题描述】:

多线程游戏服务器是怎么写的?

如果有 4 个线程,是否有 1 个线程运行游戏循环,3 个接受和处理请求?另外:信息是从运行游戏循环的线程发送的吗?

【问题讨论】:

也许吧。这取决于软件的要求和设计。没有通用的方法来做到这一点。 你是如何选择神奇数字 4 的? 这是我机器上的核心数。 不要根据核心数来选择线程数。根据您的设计选择线程数。 @Starkey:这并不像你想象的那么聪明。选择正确数量的线程更像是一门艺术而不是一门科学。事实上,现在许多操作系统都提供线程池来为您做出决定。那些明确地让线程数取决于内核数。 【参考方案1】:

Starkey 已经指出,这在很大程度上取决于精确的设计。

例如,在具有许多客户端的游戏中,您可以分配专用线程来处理输入,但对于具有少量客户端(例如

某些游戏的 NPC 具有相当高的智慧。在他们自己的线程上运行它们可能很聪明,但如果你有太多,你将需要一个线程池,以便一群 NPC 可以共享一个线程。

如果你有一个持久化的世界,你需要将状态写到硬盘的某个地方(可能通过数据库)。由于这具有严重的延迟,因此您不希望在该 I/O 上等待主游戏循环。那将是另一个线程。

最后,问题是你是否有一个 main 游戏循环。 MMO 会只有一个循环,还是有很多?

【讨论】:

如何实现多个游戏循环? 我怀疑“每个线程一个”不是您要寻找的答案。但本质上,这就是“如何”部分。我怀疑您实际上是在“为什么”之后,这是因为运行更多的事件处理循环可以让您每秒处理更多的事件。【参考方案2】:

主要是确保您的游戏逻辑不受线程模型的影响。

因此,大多数游戏服务器看起来像这样:

main() 

  gGlobalReadOnlyStuff = LoadReadOnlyStuff();

  SpawnThreads(numCores); // could be another limiting resource...
  WaitForThreadsToBeReadyToGo();

  while(1) 
     WaitForNetworkInput(networkInput);

     switch(networkInput.msg) 

     case ADMIN_THING:  // start/stop websever, dump logs, whatever...
          DoAdminThing(networkInput.params);  
          break;

     case SPAWN_GAME: // replace 'game' with 'zone' or 'instance' as needed
          idThread = ChooseBestThread(); // round robin, random, etc
          PostStartGameMessageToThread(idThread, networkInput.msg);
          break;

     // ...

     
  



void ThreadUpdate() 

   threadLocalStuff = LoadThreadLocalStuff();

   SignalThreadIsReadyToGo();   

   while(1) 

   lock(myThreadsMessageQueue);
   // copy messages to keep lock short
   localMessageQueue = threadsMessageQueue;
   unlock(myThreadsMessageQueue);

   foreach(message in localMessageQueue) 
       switch(message.msg) 
       case SPAWN_GAME:
           threadLocalStuff.games.MakeNewGame(message.params));
           break;
       case ADMIN_THING__LET_EVERYONE_KNOW_ABOUT_SERVER_RESET:
           ...;
           break;
       // etc...
       
   


   foreach(game in threadLocalStuff.games) 
       game.Update(); // game will handle its own network communication
   

然后两个困难的事情是“想出一个适合你的游戏的分区(游戏、区域、实例等)”和“在这些边界上转换东西(玩家、火球、史诗 lootz)”一个典型的答案是“通过数据库对其进行序列化”,但您可以使用套接字/消息/文件/任何东西。但是,是的,在哪里以及如何制作这些分区以及最小化可能跨越边界的内容与您的游戏设计密切相关。

(是的,根据您的设置,可能有一些“共享”系统(日志记录、内存)可能需要多线程处理(或者更好,每个线程只有一个记录器/堆)

【讨论】:

以上是关于多线程游戏服务器的基本设计?的主要内容,如果未能解决你的问题,请参考以下文章

游戏服务器框架分析

java小游戏代码及素材,技术详细介绍

构建和同步多线程游戏循环

多线程基本概念(并发与并行线程与进程)和入门案例

游戏服务器的架构演进多进程架构通信

11.1-全栈Java笔记:多线程技术的基本概念