【问题标题】:C# Sockets: Do I really need so many separate threadsC# Sockets:我真的需要这么多单独的线程吗
【发布时间】:2023-03-31 13:08:01
【问题描述】:

我正在用 C# 编写服务器。 msdn.microsoft.com 上的异步示例建议如下。

  1. BeginAccept 监听客户端(并在客户端调用时启动新线程)。
  2. BeginReceive 以接收来自客户端的数据(并启动一个新线程来执行此操作)。
  3. BeginSend 回复以向客户端发送数据(并启动另一个线程)。

此时似乎有 4 个单独的线程,从我(可能是幼稚的)的角度来看,实际上只需要 2 个。1 个用于服务器继续监听,1 个用于与客户端的对话。为什么我与客户端的对话需要 3 个线程,因为我必须在发送之前等待回复,而在等待从客户端接收数据时我不会做任何其他事情?

干杯

【问题讨论】:

  • 我认为您将线程与异步操作混淆了。
  • 附带说明:Begin* 方法是较旧的异步 API - 有一个较新的套接字异步 API
  • 这个问题密切相关:stackoverflow.com/q/21013751/1768303

标签: c# multithreading sockets


【解决方案1】:

BeginAccept 不启动新线程。它将处理程序附加到操作系统级别的挂钩。没有线程会为此操作做主要工作。 BeginReceiveBeginSend 也是如此。这些都没有开始新的线程。

当他们为其添加处理程序的事件实际触发时,会创建一个线程池线程来响应发生的操作。此处完成的 CPU 密集型工作通常应该很低。您将在此处看到大量线程池线程请求,但它们完成的工作很少,因此它们会很快被送回池中。

线程池设计用于这种类型的使用。您可以只创建 1-2 个线程并不断重复使用它们来依次响应所有这些事件,而不是为每个事件响应创建完整的线程(这很昂贵)。池只会创建尽可能多的线程来跟上足够小的积压。

【讨论】:

  • 感谢@Servy 的回复。我知道 Begin*** 在事件触发之前不会启动线程。当事情的顺序必须按顺序排列时,我仍然不明白使用池中的许多线程进行客户端对话会更好:接受等待......,接收等待......,回复等待......,接收等待。 ..等(即,如果我不等待每个段完成后再移动到下一个段,程序就可以工作)?干杯。
  • @Shanie 好吧,另一种方法是让一个线程坐在那里什么都不做,而所有操作都发生了。您将有 1 个线程花费大部分时间坐在那里无所事事。因此,您实际上需要有几个线程来执行此操作(无所事事),以跟上工作负载。单线程池线程,考虑到它只需要在有真正的 CPU 绑定工作要做时才需要被“占用”,实际上可以更快地处理请求。
  • 这很有意义@Servy。看来我需要更多地研究线程池。感谢您的帮助。
【解决方案2】:

虽然您的主线程将围绕这些操作进行编组,但您不必自己“启动线程”。 BeginAccept 是一种非阻塞方法 - .NET 将立即从中返回,但在异步完成其目的时调用线程池上的回调。 线程池在您的控制之外进行了优化。

【讨论】:

    猜你喜欢
    • 2011-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多