异步/等待高性能服务器应用程序?
C#5中新的async / await关键字看起来非常有前途,但我读了一篇关于性能对这些应用程序影响的文章,因为编译器将为异步方法生成一个非常复杂的状态机。
使用这些关键字进行异步编程要容易得多,但是对套接字来说SocketAsyncEventArgs是不是很好?
第二个问题:像Stream.WriteAsync这样的异步IO方法是非同步的(.Net上的完成端口或Mono上的epoll / poll)还是这些方法用于将写入调用推送到线程池的廉价包装器?
第三个问题:除了UI应用程序的SynchronizationContext之外,有没有办法实现某种sinlge-threaded上下文? 像事件循环之类的东西,以便在主线程上继续完成任务? 我发现了Nito.AsyncEx库,但我不确定这是否是我需要的。
async
本身非常高效。 大量的工作进入了这个。
通常,在服务器端,您关注async
I / O. 我将忽略async
CPU绑定方法,因为无论如何async
开销都会在噪声中丢失。
异步I / O将增加每个请求的内存使用量,但它会减少每个请求的线程使用量。 所以你最终获胜(边缘病态角落除外)。 对于所有异步I / O都是如此,包括async
。
await
是用一种模式设计的 – 不仅仅是Task
类型 – 所以如果你需要尽可能多地挤出性能,你可以。
我读了一篇关于性能对这些应用程序影响的文章,因为编译器会为异步方法生成一个非常复杂的状态机。
你读过 Stephen Toub的文章很棒。 我还推荐Zen of Asyncvideo (也由Stephen Toub提供)。
使用这些关键字进行异步编程要容易得多,但是对套接字来说SocketAsyncEventArgs是不是很好?
首先,要了解SocketAsyncEventArgs
的可伸缩性更高,因为它可以减少内存垃圾。 使用async
套接字的简单方法会产生更多内存垃圾,但由于await
是基于模式的,因此您可以为SocketAsyncEventArgs
API定义自己的async
兼容包装器 (如Stephen Toub的博客所示……我在这里感知一种模式)。 这使您可以挤出每一盎司的性能。
虽然从长远来看通常更好的是设计一个横向扩展系统,而不是扭曲代码以避免一些内存分配。 恕我直言。
第二个问题:像Stream.WriteAsync这样的异步IO方法是非同步的(.Net上的完成端口或Mono上的epoll / poll)还是这些方法用于将写入调用推送到线程池的廉价包装器?
我不知道Mono。 在.NET上, 大多数异步I / O方法都基于完成端口。 Stream
类是一个值得注意的例外。 默认情况下, Stream
基类将执行“廉价包装器”,但允许派生类覆盖此行为。 来自网络通信的Stream
总是覆盖它以提供真正的异步I / O. 如果流是为异步I / O显式构造的,那么处理文件的流只会覆盖它。
第三个问题:除了UI应用程序的SynchronizationContext之外,有没有办法实现某种单线程上下文?
ASP.NET也有一个SynchronizationContext
,所以如果你使用的是ASP.NET,那么你已经设置好了。
如果您正在使用自己的基于套接字的服务器(例如,Win32服务),那么您可以在我的AsyncEx库中使用AsyncContext
类型。 但这听起来并不像你真正想要的那样。 AsyncContext
将在当前线程上创建单线程上下文。 但是服务器应用程序async
的真正威力来自扩展请求而不是线程 。
考虑ASP.NET SynchronizationContext
工作原理:当每个请求进入时,它会抓取一个线程池线程并构造一个SynchronizationContext
(用于该请求 )。 当该请求具有异步工作时,它将向SynchronizationContext
注册,并且运行该请求的线程将返回到线程池。 稍后,当异步工作完成时,它会抓取线程池线程( 任何线程),在其上安装现有的SynchronizationContext
,并继续处理该请求。 最终完成请求后,将SynchronizationContext
其SynchronizationContext
。
该过程的关键是当请求等待( await
)异步操作时, 没有专用于该请求的线程。 由于与线程相比, 请求相当轻量级,因此服务器可以更好地扩展。
如果您为每个请求提供了单线程SynchronizationContext
(如AsyncContext
,则会将线程绑定到每个请求,即使它没有任何操作。 这几乎没有比同步multithreading服务器更好的了。
如果您想要发明自己的SynchronizationContext
可能会发现我的MSDN文章在SynchronizationContext
很有用。 我还在那篇文章中介绍了异步方法如何“注册”和“安装”上下文; 这主要由async void
和await
自动完成,因此您不必明确地执行此操作。
-
如果您在异步IO的上下文中使用它,那么这是一个有争议的问题。 花在数据库操作,文件/网络IO等上的时间最多为毫秒。 如果没有纳秒,
async
的开销在最坏的情况下将是微秒。 你需要小心的地方是你有很多正在等待的操作(如数千,数万或更多),这些操作非常快。 当这些异步操作代表CPU绑定工作时,使用await
的开销肯定可能至少是显而易见的。 请注意,就人类的理解能力而言,为状态机生成的代码有点复杂,但状态机通常总体上表现得相当好。 -
这些方法不仅仅是阻塞线程池线程的包装器,不是。 这将破坏
await
代表的目的。 这些方法不会阻塞任何线程并依赖OS挂钩来完成任务。 -
当然,您可以创建自己的
SynchronizationContext
而不是完全依赖UI框架提供的现有版本。 这是一个很好的例子。 使用这样的东西时要小心; 它对于正确的任务来说是一个很好的工具,但是当你应该异步地做所有事情时,可能会滥用它来找到一种更具创造性的阻塞方式。上述就是C#学习教程:异步/等待高性能服务器应用程序?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/998339.html