Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么在处理客户机请求时,异步模式比同步模式好?_C#_Asynchronous_Client Server - Fatal编程技术网

C# 为什么在处理客户机请求时,异步模式比同步模式好?

C# 为什么在处理客户机请求时,异步模式比同步模式好?,c#,asynchronous,client-server,C#,Asynchronous,Client Server,我有一个客户机-服务器项目,正在寻找更好的方法来处理来自客户机的请求。有人建议异步模式优于同步模式和线程池模式。 我的问题是为什么?异步模式有缺点吗?同步操作的一个缺点是您不能中断它们-例如,当您的服务器应用程序调用同步方法WaitForConnection()并且没有客户端连接时,您不能停止等待 例如,在同步服务器中,当访问数据结构(如果存在更新)时,您必须处理锁,这需要时间和代码(并且是难以发现的bug的来源)。同时,拥有多个(例如,数千个)线程会在许多实现中造成技术问题(例如,堆栈分配),

我有一个客户机-服务器项目,正在寻找更好的方法来处理来自客户机的请求。有人建议异步模式优于同步模式和线程池模式。

我的问题是为什么?异步模式有缺点吗?

同步操作的一个缺点是您不能中断它们-例如,当您的服务器应用程序调用同步方法WaitForConnection()并且没有客户端连接时,您不能停止等待


例如,在同步服务器中,当访问数据结构(如果存在更新)时,您必须处理锁,这需要时间和代码(并且是难以发现的bug的来源)。同时,拥有多个(例如,数千个)线程会在许多实现中造成技术问题(例如,堆栈分配),如果服务器是IO绑定的,那么这些线程几乎都处于休眠状态(等待网络)并且只是在浪费内存

在单个线程上使用异步模型,可以忽略锁定问题(这意味着处理速度尽可能快),并且只使用客户端实际需要的内存(只有一个堆栈)

然而,现在多核机器非常普遍,因此失去了部分优势(因为修改共享数据结构时必须锁定)。在N个异步服务器前面使用平衡器可能可以获得最佳效率,其中N是环境的最佳线程数


异步方法的不好的一面是,根据您的工具,代码可能非常难看和难以理解,并且如果计算不是微不足道的,并且由于错误,您的处理进入了一个无休止的循环,那么整个异步服务器将无响应(因此可能应该添加一个看门狗)。

您不想阻止UI。使用异步操作,您可以在等待服务器响应时执行其他操作。

异步模式允许您继续处理,而同步模式让您等待。

是的,异步请求通常可以在不花费线程的情况下处理。操作系统对它们有特殊的支持,如重叠I/O和完成端口。它们本质上是利用内核线程的开销,因为驱动程序需要能够处理来自多个用户模式程序的多个请求,所以无论如何都需要内核线程。NET框架在其BeginXxx()方法中很容易利用这一点

使用threadpool线程也很便宜,但您必须遵守threadpool调度程序的行为。这与启动更多的TP线程(然后有内核)不同。TP线程永远不应该用于可能被阻塞一段时间的代码,这对于CS任务(如建立连接)非常典型

异步代码中的错误处理非常困难。当EndXxxx()方法引发异常时,通常只有很少的上下文。它发生在回调线程上,远离主逻辑。好吧,当你可以耸耸肩说“没有发生,让我们记录下来”,当程序的状态取决于它时,完全是混乱和愤怒。在后一种情况下,请始终选择同步模式。

与Hans的答案一起“标记”:I/O操作与线程的独立性允许更显著的扩展;数以万计的未完成请求是可能的,这是使用线程无法完成的

此外,当您开始时,异步方法的复杂性远低于正确编写同步代码的复杂性。大多数同步套接字代码看起来更简单,但实际上包含一些微妙的错误

如果双方发送的数据多于读取的数据,异步方法对于防止死锁情况也很重要;有关更多讨论,请参阅


如果您喜欢线程安全包中异步I/O的性能优势和(大部分)性能的好处(更简单的错误处理),请考虑库。< /P>异步不能解决锁定问题。异步回调可以由不同线程上的多个回调重新输入。在使用异步模型时,您仍然需要保护任何共享状态。使用抢占式多线程编码正确锁定的问题在于切换是“不可见的”,并且可以随时发生。异步实现中的切换点是固定的,通常是绝对明显的。由于确定性,调试也简单得多。虽然仍然可能存在某种形式的“逻辑”锁定,但在我看来,这与在共享数据更新方法中获得正确锁定的难度相比是微不足道的。@heavyd:在我看来,重新阅读您的评论似乎存在术语问题。我说过,使用单线程异步实现,您可以忘记锁定问题。。。(这意味着关于并发访问的物理锁定,而不是自动机状态更改之间的逻辑锁定,当然这是强制性的),并且如果异步与单线程不耦合,那么这一优势就失去了。在你的评论中,你谈到了不同的线程,因此可能对这些术语有一些误解。+1,它们甚至比+1更好:通常不需要内核线程(大多数驱动程序甚至没有线程)。答案简单明了,但有足够的解释力。谢谢@Brian