2011-09-19 28 views
6

试图找出我是否应该使用异步方法或没有如:是否有必要使用异步开始/结束方法(如果已经在单独的线程上)?

,而不是他们的同步TcpListener.AcceptTcpClientNetworkStream.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();

而且好像异步版本将有更多的开销,因为不必创建另一个线程。 (基本上,每个连接都会有一个线程,然后在读取该线程时也会有另一个线程。)。

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

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

如果我错了,请纠正我。我对线程仍然很陌生,我试图理解这一切。然而,在这种情况下,它似乎使用普通的同步方法,只是阻塞线程将是最佳的解决方案?

回答

4

TcpListener.AcceptTcpClient块的线程,直到建立了连接,所以没有浪费的CPU周期。

但也没有他们顺利地完成。线程是一个非常昂贵的操作系统对象,大约是最昂贵的。当线程阻塞连接请求时,程序正在使用内存不超过兆字节。

然而,这些方法将在单独的工作线程调用,因为它是如此,没有那

任务的威胁是不是一个好的解决方案,它使用一个线程池线程,但该线程将阻止。线程池管理器试图保持运行的TP线程的数量等于机器上的CPU核心数量。 TP线程长时间阻塞时,这样做效果不佳。它阻止其他有用的工作由等待轮到的其他TP线程完成。

BeginAcceptTcpClient()使用所谓的I/O完成回调。当套接字正在侦听时,没有系统资源被消耗。一旦连接请求进入,操作系统就会运行一个APC(异步过程调用),它抓取一个线程池线程来进行回调。线程本身通常使用几微秒。非常有效。

这种代码将获得在C#的下一个版本简单了很多下一个异步等待关键字。也许是年底。

3

如果您致电AcceptTcpClient()任何线程,该线程是无用的,直到您获得连接。

如果您致电BeginAcceptTcpClient(),调用线程可以立即停止,而不会浪费线程。

这在使用ThreadPool(或TPL)时尤为重要,因为它们使用有限数量的池线程。
如果你有太多的线程在等待操作,你可以用完线程池线程,这样新的工作项将不得不等待,直到其他线程完成。

相关问题