在服务器上使用线程与异步编程

Using Threading vs Asynchronous programming on a server

我正在空闲时间用 C# 开发一个小型多人游戏。

我读过线程和异步编程很相似,但是在编写等待新连接并同时为现有连接提供服务的服务器时,我应该使用它们中的哪一个?

一开始我采用的是异步方式,但后来我读到它主要用于IO目的。这让我怀疑它是否适合这样的情况。

谢谢。

简单来说,在幕后 async/await 可以是线程 - 框架根据您的提示决定继续任务是否 运行 在同一个线程上,或者分配一个如果需要,将整个线程分配给任务。调度器手上有线程和线程池。但是使用任务通常比线程更容易管理,而且最重要的是,性能更高。 OS 线程的成本很高,而托管线程则不是。是的,它在IO绑定操作中发挥了最大的作用,但是网络通信不就是IO吗?无论如何,由于上述原因,如果您使用 Tasks 而不是 treads,您手头就有相同的同步工具,甚至更多。举个例子,Kestrel 和 Katana 服务器都是基于任务的。

一般两个都可以用,因为你的网络IO很大。但我不喜欢 async/await,因为它迫使你几乎在整个应用程序中使用 async/await。

async/await 和使用 thread/threadpool 的主要区别在于 async/await 是由调用线程执行的,它旨在处理延迟,而第二个会做在空闲线程上工作并降低创建线程的成本,它应该使用线程池。

一切都是有代价的。为 async/await 设置状态机需要时间,设置线程也需要时间。但是使用线程池可以降低这些成本。

像别人写的async/await可以使用线程,但一般不会。 一个设计良好的游戏服务器将有一个线程来处理传入的连接和一个线程池来处理与客户端的通信。 我建议您采用这种方式,因为它已被多次证明,当您想要处理数千个客户端或需要巨大的吞吐量时,这就是您必须采用的方式。

顺便说一句:产生许多任务会给您带来与产生许多线程时相同的问题,因此不是一个好的解决方案。这里的关键字是"context switch",你应该读一下。