如果已经在单独的线程上,是否有必要使用异步开始/结束方法?

Joh*_*ith 6 c# multithreading tcp

试图弄清楚我是否应该使用异步方法,例如:

和

而不是他们的同步TcpListener.AcceptTcpClient和NetworkStream.Read版本.我一直在寻找相关的线程,但我仍然有点不确定一件事:

问题:使用异步方法的主要优点是GUI没有被锁定.但是,这些方法将在单独的Task线程上调用,因为它没有任何威胁.此外,TcpListener.AcceptTcpClient阻塞线程直到建立连接,因此不会浪费CPU周期.既然如此,为什么这么多人总是建议使用异步版本?在这种情况下,似乎同步版本会更优秀吗?

此外,使用异步方法的另一个缺点是增加了对象的复杂性和不断的转换.例如,必须这样做:

private void SomeMethod()
{
    // ...

    listener.BeginAcceptTcpClient(OnAcceptConnection, listener);
}

private void OnAcceptConnection(IAsyncResult asyn)
{
    TcpListener listener = (TcpListener)asyn.AsyncState;

    TcpClient client = listener.EndAcceptTcpClient(asyn);
}
Run Code Online (Sandbox Code Playgroud)

与此相反:

TcpClient client = listener.AcceptTcpClient();

此外,由于必须创建另一个线程,异步版本似乎会有更多的开销.(基本上,每个连接都有一个线程,然后在读取该线程时也会有另一个线程.Threadception!)

此外,还有TcpListener的装箱和拆箱以及与创建,管理和关闭这些额外线程相关的开销.

基本上,通常情况下只有单独的线程来处理单个客户端连接,现在就有,然后为每种类型的操作执行一个额外的线程(读取/写入流数据并在服务器端侦听新连接)

如果我错了,请纠正我.我仍然是线程新手,我试图理解这一切.但是,在这种情况下,似乎使用正常的同步方法,只是阻塞线程将是最佳解决方案?

Han*_*ant 4

TcpListener.AcceptTcpClient 会阻塞线程,直到建立连接为止,因此不会浪费 CPU 周期。

但也没有任何工作完成。线程是一个非常昂贵的操作系统对象,几乎是最昂贵的。当线程因连接请求而阻塞时,您的程序正在消耗一兆字节的内存而未使用它。

但是,这些方法将在单独的任务线程上调用,因此不存在这种威胁

Task 也不是一个好的解决方案,它使用线程池线程,但线程会阻塞。线程池管理器尝试保持正在运行的 TP 线程数等于机器上的 cpu 核心数。当 TP 线程长时间阻塞时,这将无法很好地工作。它阻止其他等待轮到的 TP 线程完成其他有用的工作。

BeginAcceptTcpClient() 使用所谓的 I/O 完成回调。套接字侦听时不会消耗任何系统资源。一旦有连接请求到来,操作系统就会运行 APC(异步过程调用),它会获取线程池线程来进行回调。线程本身的使用时间通常为几微秒。非常高效。

在下一版本的 C# 中,使用下一个async和await关键字,此类代码将变得更加简单。年底吧,也许吧。