Multithreading 多线程还是尽可能少的线程?

Multithreading 多线程还是尽可能少的线程?,multithreading,language-agnostic,client-server,Multithreading,Language Agnostic,Client Server,作为一个辅助项目,我目前正在为一个我曾经玩过的古老游戏编写一个服务器。我试图使服务器尽可能松散耦合,但我想知道对于多线程来说,什么是一个好的设计决策。目前,我的行动顺序如下: 启动(创建)-> 服务器(侦听客户端,创建)-> 客户端(侦听命令并发送周期数据) 我假设平均有100个客户,因为这是游戏在任何给定时间的最大值。对于整个事情的线程化,什么是正确的决定?我当前的设置如下: 在服务器上侦听新连接的1个线程,在新连接上创建一个客户端对象并再次开始侦听 客户端对象有一个线程,侦听传入的命令

作为一个辅助项目,我目前正在为一个我曾经玩过的古老游戏编写一个服务器。我试图使服务器尽可能松散耦合,但我想知道对于多线程来说,什么是一个好的设计决策。目前,我的行动顺序如下:

  • 启动(创建)->
  • 服务器(侦听客户端,创建)->
  • 客户端(侦听命令并发送周期数据)
我假设平均有100个客户,因为这是游戏在任何给定时间的最大值。对于整个事情的线程化,什么是正确的决定?我当前的设置如下:

  • 在服务器上侦听新连接的1个线程,在新连接上创建一个客户端对象并再次开始侦听
  • 客户端对象有一个线程,侦听传入的命令并发送周期性数据。这是使用非阻塞套接字完成的,因此它只需检查是否有可用数据,处理这些数据,然后发送已排队的消息。登录在发送-接收周期开始之前完成
  • 游戏本身的一个线程(我现在认为它与整个客户端服务器部分分开),从架构上讲。
这将导致总共102个线程。我甚至考虑给客户端两个线程,一个用于发送,一个用于接收。如果我这样做,我可以在接收方线程上使用阻塞I/O,这意味着在一般情况下,线程将大部分处于空闲状态

我主要担心的是,通过使用这么多线程,我将占用大量资源。我不担心比赛条件或僵局,因为这是我无论如何都要处理的事情

我的设计是这样设置的,我可以为所有客户端通信使用单个线程,无论它是1还是100。我已将通信逻辑与客户机对象本身分离,因此可以实现它,而无需重写大量代码

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

谢谢


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


根据我在这里得到的答案(上下文切换是我一直在思考的性能问题,但直到你指出这一点我才知道,谢谢!)我想我会选择一个听众、一个接收者、一个发送者和一些其他东西;-)

使用事件流/队列和线程池来保持平衡;这将更好地适应具有更多或更少内核的其他机器

一般来说,活动线程比内核多很多,这会浪费时间进行上下文切换


如果您的游戏包含许多短动作,循环/循环事件队列将比固定数量的线程提供更好的性能

我认为您应该问的问题不是200作为一般线程数是好是坏,而是有多少线程将处于活动状态

如果在某一时刻只有几个人在活动,而其他人都在睡觉或等待,那么你就没事了。在这种情况下,休眠线程不需要任何成本


但是,如果这200个线程都处于活动状态,您的CPU将浪费大量时间在这200个线程之间进行线程上下文切换。

我是在.NET中编写的,我不确定我编写代码的方式是否是由于.NET限制和它们的API设计,或者这是否是一种标准方式,但我过去就是这样做的:

  • 将用于处理传入数据的队列对象。这应该在队列线程和工作线程之间同步锁定,以避免争用情况

  • 用于处理队列中数据的工作线程。对数据队列进行排队的线程使用信号量通知该线程处理队列中的项目。此线程将在任何其他线程之前启动自身,并包含一个连续循环,该循环可以一直运行,直到收到关闭请求为止。循环中的第一条指令是暂停/继续/终止处理的标志。该标志最初将设置为暂停,以便线程处于空闲状态(而不是连续循环),而不进行任何处理。当队列中有要处理的项目时,队列线程将更改标志。然后,该线程将在循环的每次迭代中处理队列中的单个项。当队列为空时,它将把标志设置回pause,以便在循环的下一次迭代中,它将等待,直到队列进程通知它还有更多的工作要做

  • 一个连接侦听器线程,用于侦听传入的连接请求并将这些请求传递给

  • 创建连接/会话的连接处理线程。在连接侦听器线程中有一个单独的线程意味着,在该线程处理请求时,由于资源减少,您正在减少丢失连接请求的可能性

  • 侦听当前连接上的传入数据的传入数据侦听器线程。所有数据都被传递到排队线程,以便排队处理。您的侦听器线程应该尽可能少地执行基本侦听和传递数据以进行处理之外的操作

  • 一个排队线程,它以正确的顺序将数据排队,以便所有内容都能正确处理。该线程将信号量提升到处理队列,让它知道有数据要处理。将此线程与传入数据侦听器分离意味着