试图弄清楚我是否应该使用异步方法,例如:
和
相对于它们的同步 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);
}
与此相反:
TcpClient client = listener.AcceptTcpClient();
另外,由于必须创建另一个线程,异步版本似乎会有更多的开销。 (基本上,每个连接都会有一个线程,然后在读取该线程时也会有另一个线程。Threadception!)
此外,还有 TcpListener 的装箱和拆箱以及与创建、管理和关闭这些额外线程相关的开销。
基本上,通常只有单独的线程来处理单独的客户端连接,现在有一个线程,然后为执行的每种类型的操作(读/写流数据和监听服务器端的新连接)创建一个额外的线程
如有错误请指正。我对线程仍然是新手,我正在努力理解这一切。但是,在这种情况下,似乎使用普通的同步方法并仅阻塞线程才是最佳解决方案?
最佳答案
TcpListener.AcceptTcpClient blocks the thread until a connection is made so there is no wasted CPU cycles.
但也没有完成任何工作。 Thread 是一个非常昂贵的操作系统对象,几乎是最昂贵的。当线程在连接请求时阻塞时,您的程序正在消耗 1 兆字节的内存而没有使用它。
However, these methods will be called on separate Task threads as it is so there is no threat of that
Task 也不是一个好的解决方案,它使用线程池线程但线程会阻塞。线程池管理器试图保持运行的 TP 线程数等于机器上的 cpu 内核数。当 TP 线程长时间阻塞时,这将无法正常工作。它会阻止其他等待轮到它们的 TP 线程完成其他有用的工作。
BeginAcceptTcpClient() 使用所谓的 I/O 完成回调。套接字监听时不会消耗系统资源。一旦连接请求进来,操作系统就会运行一个 APC(异步过程调用),它会捕获一个线程池线程进行回调。线程本身的使用时间通常为几微秒。非常有效。
在下一个 async 和 await 关键字的下一个 C# 版本中,这种代码将变得更加简单。也许是年底。
关于c# - 如果已经在单独的线程上,是否有必要使用异步开始/结束方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7477596/