异步等待Task.Delay显着降低了基于HttpListener的服务器的带宽

时间:2018-02-09 15:25:28

标签: c# .net multithreading asynchronous

我使用 System.Net 命名空间中的标准 HttpListener 。当我使用 Task.Delay 来模拟服务器端的一些工作(没有等待)和使用Apache基准测试服务器时,它会提供良好的结果(2000 rps)。但是当我等待"等待"带宽约为9 rps(根据Apache Benchmark)。为什么它会像这样?欣赏答案。

private async Task Listen()
{
    while (listener.IsListening)
    {
        try
        {
            var context = await listener.GetContextAsync().ConfigureAwait(false);

            context.Response.StatusCode = (int)HttpStatusCode.OK;
            // good without await
            await Task.Delay(100).ConfigureAwait(false);

            using (var sw = new StreamWriter(context.Response.OutputStream))
            {
                await sw.WriteAsync("<html><body>Hello</body></html>");
                await sw.FlushAsync();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

public async Task Run()
{
    listener.Start();
    Task.Run(() => Listen());
}

3 个答案:

答案 0 :(得分:4)

这是因为您插入的暂停会延迟循环。

您只接受该行的请求:

await listener.GetContextAsync()

在同一个循环中。

这意味着您必须等待上一个请求完成才能接受新的上下文。

最有可能的是,您希望同时处理接受的上下文。为了达到这个目的,你应该在一个紧密的循环中接受上下文,然后将请求的处理分离到另一个没有“挂起”的地方。接受循环。

在最简单的情况下,你可以发现并忘记&#34; ......

while (listener.IsListening)
{
    var context = await listener.GetContextAsync().ConfigureAwait(false);
    HandleContextAsync(context); //note: not awaited
}

...实际上,您需要更加思考如何跟踪HandleContextAsync方法中的异常。

答案 1 :(得分:1)

创建Delay()任务并允许其在自己的时间运行,而不会进一步影响创建方法。如果您在该任务上既没有await(异步)或Wait()(同步),那么创建方法会立即继续,使其显示为“快速”。 await 实际上等待延迟任务完成,但是这样做意味着线程不会阻塞并且可以同时执行其他工作。您的其他版本并非等待,同步或其他方式。延迟任务被创建并运行,但由于没有其他任何事情在它完成时关心,它只是被执行并且垃圾收集在该方法中不再发挥作用。

答案 2 :(得分:0)

这是因为您在处理下一个请求之前等待了100毫秒,因此您每秒最多可处理10个请求。没有等待的Task.Delay根本不会影响你的应用程序,你可以删除这一行,结果仍然是每秒处理2000个请求。