Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.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# 使用async/await返回异步HtpListener并处理高负载的简单任务_C#_.net_Http_Httplistener_System.net - Fatal编程技术网

C# 使用async/await返回异步HtpListener并处理高负载的简单任务

C# 使用async/await返回异步HtpListener并处理高负载的简单任务,c#,.net,http,httplistener,system.net,C#,.net,Http,Httplistener,System.net,我创建了以下简单的HttpListener,以同时服务多个请求(在.NET 4.5上): 类程序{ 静态void Main(字符串[]参数){ HttpListener=新的HttpListener(); Add(“http://+:8088/”; listener.Start(); ProcessAsync(侦听器).ContinueWith(任务=>{}); Console.ReadLine(); } 静态异步任务ProcessAsync(HttpListener侦听器){ HttpList

我创建了以下简单的
HttpListener
,以同时服务多个请求(在.NET 4.5上):

类程序{
静态void Main(字符串[]参数){
HttpListener=新的HttpListener();
Add(“http://+:8088/”;
listener.Start();
ProcessAsync(侦听器).ContinueWith(任务=>{});
Console.ReadLine();
}
静态异步任务ProcessAsync(HttpListener侦听器){
HttpListenerContext ctx=await listener.GetContextAsync();
//让另一位听众听录音
Task.Factory.StartNew(()=>ProcessAsync(侦听器));
//模拟长时间运行
睡眠(1000);
//表演
执行(ctx);
等待ProcessAsync(侦听器);
}
静态void执行(HttpListenerContext ctx){
HttpListenerResponse=ctx.response;
string responseString=“你好,世界!”;
byte[]buffer=Encoding.UTF8.GetBytes(responseString);
//获取响应流并将响应写入其中。
response.ContentLength64=buffer.Length;
流输出=response.OutputStream;
输出.写入(缓冲区,0,缓冲区.长度);
//必须关闭输出流。
output.Close();
}
}
我使用ApacheBenchmark工具对此进行负载测试。当我发出1请求时,请求的最大等待时间为1秒。例如,如果我发出10个请求,响应的最大等待时间将达到2秒

您将如何更改我的上述代码以使其尽可能高效

编辑

在@JonSkeet的回答之后,我更改了代码如下。起初,我试图模拟阻塞调用,但我想这是核心问题。所以,我接受了@JonSkeet的建议,并将其改为Task.Delay(1000)。现在,下面的代码给出了10个并发请求的最大等待时间约为1秒:

class Program {

    static bool KeepGoing = true;
    static List<Task> OngoingTasks = new List<Task>();

    static void Main(string[] args) {

        HttpListener listener = new HttpListener();
        listener.Prefixes.Add("http://+:8088/");
        listener.Start();
        ProcessAsync(listener).ContinueWith(async task => {

            await Task.WhenAll(OngoingTasks.ToArray());
        });

        var cmd = Console.ReadLine();

        if (cmd.Equals("q", StringComparison.OrdinalIgnoreCase)) {
            KeepGoing = false;
        }

        Console.ReadLine();
    }

    static async Task ProcessAsync(HttpListener listener) {

        while (KeepGoing) {
            HttpListenerContext context = await listener.GetContextAsync();
            HandleRequestAsync(context);

            // TODO: figure out the best way add ongoing tasks to OngoingTasks.
        }
    }

    static async Task HandleRequestAsync(HttpListenerContext context) {

        // Do processing here, possibly affecting KeepGoing to make the 
        // server shut down.

        await Task.Delay(1000);
        Perform(context);
    }

    static void Perform(HttpListenerContext ctx) {

        HttpListenerResponse response = ctx.Response;
        string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
        byte[] buffer = Encoding.UTF8.GetBytes(responseString);

        // Get a response stream and write the response to it.
        response.ContentLength64 = buffer.Length;
        Stream output = response.OutputStream;
        output.Write(buffer, 0, buffer.Length);

        // You must close the output stream.
        output.Close();
    }
}
类程序{
静态bool KeepGoing=true;
静态列表OngoingTasks=新列表();
静态void Main(字符串[]参数){
HttpListener=新的HttpListener();
Add(“http://+:8088/”;
listener.Start();
ProcessAsync(侦听器).ContinueWith(异步任务=>{
等待任务。何时(持续的任务。ToArray());
});
var cmd=Console.ReadLine();
if(cmd.Equals(“q”,StringComparison.OrdinalIgnoreCase)){
KeepGoing=false;
}
Console.ReadLine();
}
静态异步任务ProcessAsync(HttpListener侦听器){
同时(继续){
HttpListenerContext=await listener.GetContextAsync();
HandleRequestAsync(上下文);
//TODO:找出将正在进行的任务添加到OnGoingTask的最佳方法。
}
}
静态异步任务HandleRequestAsync(HttpListenerContext上下文){
//在此处进行处理,可能会影响KeepGoing以使
//服务器关闭。
等待任务。延迟(1000);
执行(上下文);
}
静态void执行(HttpListenerContext ctx){
HttpListenerResponse=ctx.response;
string responseString=“你好,世界!”;
byte[]buffer=Encoding.UTF8.GetBytes(responseString);
//获取响应流并将响应写入其中。
response.ContentLength64=buffer.Length;
流输出=response.OutputStream;
输出.写入(缓冲区,0,缓冲区.长度);
//必须关闭输出流。
output.Close();
}
}

在我看来,你最终会遇到听众的分歧。在
ProcessAsync
中,启动一个新任务进行侦听(通过task.Factory.StartNew),然后在方法末尾再次调用
ProcessAsync
。那怎么可能结束呢?目前还不清楚这是否是导致性能问题的原因,但总体来看,这显然是一个问题

我建议将代码更改为一个简单的循环:

static async Task ProcessAsync(HttpListener listener) {
    while (KeepGoing) {
        var context = await listener.GetContextAsync();
        HandleRequestAsync(context);         
    }
}

static async Task HandleRequestAsync(HttpListenerContext context) {
    // Do processing here, possibly affecting KeepGoing to make the 
    // server shut down.
}
现在,上述代码忽略了
HandleRequestAsync
的返回值。您可能希望保留“当前正在运行”任务的列表,当您被要求关闭时,请使用
wait Task.whall(inFlightTasks)
,以避免服务器过早关闭


还要注意
Thread.Sleep
是一个阻塞延迟。异步延迟是等待任务。延迟(1000)

谢谢Jon!我故意把阻塞延迟放在那里,是为了模拟阻塞操作,看看它将如何处理这些操作。@tugberk:但是,由于目前编写代码的方式,阻塞操作有时可能会阻塞接受线程(我认为)。如果您试图对繁重的CPU工作进行建模,那么您应该在单独的任务中完成CPU工作,然后等待该任务。如果您试图对IO建模,那么应该异步等待。您是对的。核心问题是(我猜)我所做的阻塞“睡眠”。我编辑了我的问题并将新代码放在那里。它仍然遗漏了一些重要的步骤(我猜是这样的),但多亏了您,现在情况更好了。我正在寻找一个实现
inFlightTasks
的示例<代码>列表不起作用,因为它不是线程安全的。我已经看了
ConcurrentBag
,但我不知道如何删除已完成的任务,因为该类上没有
remove
方法,而且
TryTake
似乎不允许指定要执行的项目。@CoderDennis:听起来你应该问一个新问题,并提供更多细节。谢谢你提供了完整的解决方案。@jonsket需要什么修改需要上述模式才能允许它服务于服务器发送的事件,在这种情况下,响应流永远不会真正“关闭”。例如,我们如何使用它来“持续推送”数据到连接的客户端?@CharlesO我没有尝试过,但我假设如果您不调用
output.Close()static async Task ProcessAsync(HttpListener listener) {
    while (KeepGoing) {
        var context = await listener.GetContextAsync();
        HandleRequestAsync(context);         
    }
}

static async Task HandleRequestAsync(HttpListenerContext context) {
    // Do processing here, possibly affecting KeepGoing to make the 
    // server shut down.
}