multithreading - 线程多还是线程少?

标签 multithreading language-agnostic client-server

作为辅助项目,我目前正在为我玩过的古老游戏编写服务器。我正在尝试使服务器尽可能松散地耦合,但是我想知道对于多线程而言,一个好的设计决定是什么?目前,我有以下操作顺序:

  • 启动(创建)->
  • 服务器(监听客户端,创建)->
  • 客户端(监听命令并发送期间数据)

  • 我假设平均有100个客户,因为这是该游戏在任何给定时间的最高人数。对于整个线程的处理,正确的决定是什么?我当前的设置如下:

    服务器上的
  • 1个线程用于监听新连接,在新连接上创建一个客户端对象,然后再次开始监听。
  • 客户端对象具有一个线程,用于监听传入的命令并发送定期数据。这是使用非阻塞套接字完成的,因此它仅检查是否有可用数据,进行处理,然后发送已排队的消息。在发送-接收周期开始之前完成登录。
  • 游戏本身的一个线程(目前),就体系结构而言,我认为该线程与整个客户端-服务器部分是分开的。

  • 这将导致总共102个线程。我什至考虑给客户端2个线程,一个用于发送,一个用于接收。如果这样做,则可以在接收器线程上使用阻塞I/O,这意味着在一般情况下该线程将大部分处于空闲状态。

    我主要担心的是,通过使用这么多线程,我将浪费资源。我不必担心比赛条件或僵局,因为无论如何我都必须解决这一问题。

    我的设计是以这样一种方式设置的:可以使用一个线程进行所有客户端通信,无论是1还是100。我已经将通信逻辑与客户端对象本身分离开了,因此我可以实现它而不必重写很多代码。

    主要问题是:在一个应用程序中使用200个以上的线程是否错误?有优势吗?我正在考虑在多核计算机上运行它,是否会充分利用像这样的多核的优势?

    谢谢!

    在所有这些线程中,大多数将通常被阻塞。我预计连接速度不会超过每分钟5次。来自客户端的命令很少出现,平均每分钟20条。

    按照我得到的答案(上下文切换是我一直在考虑的性能问题,但是直到您指出来,我才知道,谢谢!)我想我会选择一个听众,一个听众。接收者,一个发送者和一些杂物;-)

    最佳答案

    我使用.NET编写,因此不确定代码的编写方式是否是由于.NET限制及其API设计所致,还是不确定这是一种标准的处理方式,但这是我如何在.NET中完成此类操作过去:

  • 将用于处理传入数据的队列对象。这应该在排队线程和工作线程之间同步锁定,以避免出现竞争情况。
  • 用于处理队列中数据的工作线程。将数据队列排队的线程使用信号量来通知该线程处理队列中的项目。该线程将在其他线程之前启动,并包含一个可以运行直到收到关闭请求的连续循环。循环中的第一条指令是一个标志,用于暂停/继续/终止处理。该标志最初将设置为暂停,以便线程处于空闲状态(而不是连续循环),而无需执行任何处理。当队列中有要处理的项目时,排队线程将更改标志。然后,该线程将在循环的每次迭代中处理队列中的单个项目。当队列为空时,它将标志设置回暂停,以便在循环的下一次迭代时,它将等待直到排队过程通知它还有更多工作要做。
  • 一个连接监听器线程,用于监听传入的连接请求并将这些请求传递给...
  • 创建连接/ session 的连接处理线程。与连接监听器线程具有单独的线程意味着,由于该线程在处理请求时减少了资源,因此减少了丢失连接请求的可能性。
  • 传入数据监听器线程,用于监听当前连接上的传入数据。所有数据都传递到排队线程以排队等待处理。您的监听器线程应该在基本监听和将数据传递给处理之外执行尽可能少的操作。
  • 一个排队线程,以正确的顺序将数据排队,以便可以正确处理所有内容,此线程将信号量提高到处理队列,以使其知道要处理的数据。将此线程与传入数据监听器分开,意味着您不太可能错过传入数据。
  • 在方法之间传递的一些 session 对象,以便每个用户的 session 在整个线程模型中都是自包含的。

  • 这样可以使线程简化为我所知道的那样简单但健壮的模型。我很想找到一个比这个更简单的模型,但是我发现,如果我尝试进一步减少线程模型,就会开始丢失网络流上的数据或丢失连接请求。

    它还有助于TDD(测试驱动开发),以便每个线程都在处理单个任务,并且更容易为测试编写代码。具有数百个线程可能很快成为资源分配的噩梦,而具有单个线程则成为维护的噩梦。

    保持每个逻辑任务一个线程的方式与在TDD环境中每个任务只有一种方法的方式简单得多,并且您可以在逻辑上分离每个任务应该做什么。发现潜在问题更容易,而解决它们也容易得多。

    关于multithreading - 线程多还是线程少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/375374/

    相关文章:

    multithreading - Delphi:系统错误1158的原因(当前进程没有更多的系统句柄)

    带返回值的对象内的java线程方法

    c++ - 如何使一个线程 "promptly"中的内存存储在其他线程中可见?

    language-agnostic - "lazy evaluation"和 "reactive programming"

    java - 在与邻居对应的区域中随机选择点,避免无限递归

    terminal - 如何阻止 ANSI 颜色代码弄乱 printf 对齐?

    Java 一个生产者和两个消费者

    c - 如何作为具有多个客户端的服务器运行游戏?

    c - 使用 fnctl() 锁定和解锁文件以进行读写(多个进程)

    javascript - Socket.io 和 Nodejs : Sending response to multiple clients and change not being saved(? )