首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >异步/等待高性能服务器应用程序?

异步/等待高性能服务器应用程序?
EN

Stack Overflow用户
提问于 2013-02-07 05:51:56
回答 2查看 7K关注 0票数 14

C# 5中新的异步/等待关键字看起来非常有前途,但我读到了一篇关于这些应用程序性能影响的文章,因为编译器将为异步方法生成一个相当复杂的状态机。

使用这些关键字进行异步编程要容易得多,但它真的像SocketAsyncEventArgs for Sockets一样好吗?

第二个问题:像Stream.WriteAsync这样的异步IO方法真的是异步的( .Net上的完成端口或者Mono上的epoll/poll ),或者这些方法是用于将写调用推送到线程池的廉价包装器吗?

第三个问题:除了UI应用程序的SynchronizationContext之外,有没有办法实现某种单线程上下文?像事件循环这样的东西,让完成的任务在主线程上继续吗?我发现了Nito.AsyncEx库,但我不太确定这是否是我所需要的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-02-07 08:33:40

async本身的性能相当好。为此做了大量的工作。

通常,在服务器端,您关心的是CPU/O。我将忽略async占用async的方法,因为不管怎样,async开销都会消失在噪声中。

异步I/O会增加每个请求的内存使用量,但会减少每个请求的线程使用量。所以你最终赢了(除了边缘的病态角落案例)。所有异步I/O都是如此,包括async

await是用一种模式设计的--不仅仅是Task类型--所以如果你需要尽可能多地提高性能,你可以做到。

我读过一篇关于这些应用程序性能影响的文章,因为编译器将为异步方法生成一个相当复杂的状态机。

Stephen Toub的article you read非常出色。我也推荐Zen of Async video (也是Stephen Toub写的)。

使用这些关键字进行

异步编程要容易得多,但它真的像SocketAsyncEventArgs for Sockets一样好吗?

首先,要了解SocketAsyncEventArgs的可扩展性更强,因为它减少了内存垃圾。使用async套接字的简单方法会产生更多的内存垃圾,但是由于await是基于模式的,你可以使用define your own async-compatible wrappers for the SocketAsyncEventArgs API (见Stephen Toub的博客...我在这里感觉到一种模式;)。这允许您挤出性能的每一盎司。

不过,从长远来看,设计一个横向扩展系统通常比扭曲代码来避免一些内存分配更好。我的天。

第二个问题:像Stream.WriteAsync这样的异步IO方法真的是异步的( .Net上的完成端口或Mono上的epoll/poll ),或者这些方法是用于将写调用推送到线程池的廉价包装器吗?

我不知道Mono怎么样。在.NET上,大多数异步I/O方法都基于完成端口。Stream类是一个值得注意的例外。默认情况下,Stream基类将执行“廉价包装”,但允许派生类覆盖此行为。来自网络通信的Stream始终覆盖此以提供真正的异步I/O。如果流是为异步I/O显式构造的,则仅处理文件的Stream才会覆盖此。

第三个问题:除了UI应用程序的SynchronizationContext之外,还有实现某种单线程上下文的方法吗?

ASP.NET也有一个SynchronizationContext,所以如果你正在使用ASP.NET,你已经设置好了。

如果您正在开发自己的基于套接字的服务器(例如,Win32服务),那么您可以使用我的AsyncEx库中的AsyncContext类型。但这听起来并不是你真正想要的。AsyncContext将在当前线程上创建单线程上下文。但async对服务器应用程序的真正威力来自于扩展请求,而不是线程。

考虑一下ASP.NET SynchronizationContext是如何工作的:当每个请求进来时,它获取一个线程池线程并构造一个SynchronizationContext (针对该请求)。当该请求有异步工作要做时,它向SynchronizationContext注册,运行该请求的线程返回到线程池。稍后,当异步工作完成时,它将获取一个线程池线程(任何线程),在其上安装现有的SynchronizationContext,并继续处理该请求。当请求最终完成时,它的SynchronizationContext被释放。

该过程中的关键是,当请求正在等待(await)异步操作时,没有专用于该请求的线程。因为与线程相比,请求是相当轻量级的,这使得服务器能够更好地伸缩。

如果您为每个请求提供了一个单线程SynchronizationContext,例如AsyncContext,这将为每个请求绑定一个线程,即使它没有任何事情可做。这并不比同步多线程服务器好多少。

如果你想发明你自己的MSDN article on SynchronizationContext,你可能会发现我的SynchronizationContext很有用。我还在那篇文章中介绍了异步方法如何“注册”和“安装”上下文;这主要是由async voidawait自动完成的,因此您不必显式完成。

票数 32
EN

Stack Overflow用户

发布于 2013-02-07 06:16:58

  1. ,如果你在异步IO的上下文中使用它,这是一个没有意义的问题。花在数据库操作、文件/网络IO等上的时间充其量是毫秒。如果没有纳秒,async的开销在最坏的情况下将是微秒。您需要小心的是,当您有许多操作正在等待时(如数千、数万或更多),并且这些操作非常快。当这些异步操作代表CPU受限的工作时,使用await的开销至少是可以注意到的。请注意,从人类可理解性的角度来看,为状态机生成的代码有些复杂,但状态机总体上往往执行得相当好。
  2. 这些方法不仅仅是阻塞线程池线程的包装器。这将违背await所代表的目的。这些方法不会阻塞任何线程并依赖于操作系统钩子来完成任务。
  3. 当然,您可以创建自己的SynchronizationContext,而不是完全依赖于UI框架提供的现有钩子。Here就是一个很好的例子。在使用这样的东西时要小心;对于正确的任务,它是一个很好的工具,但它可能会被滥用来寻找更具创造性的阻塞方法,而实际上你应该做所有的事情asynchronously.
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14739517

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档