【发布时间】:2012-11-22 11:52:12
【问题描述】:
我创建了以下简单的HttpListener 来同时处理多个请求(在 .NET 4.5 上):
class Program {
static void Main(string[] args) {
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://+:8088/");
listener.Start();
ProcessAsync(listener).ContinueWith(task => { });
Console.ReadLine();
}
static async Task ProcessAsync(HttpListener listener) {
HttpListenerContext ctx = await listener.GetContextAsync();
// spin up another listener
Task.Factory.StartNew(() => ProcessAsync(listener));
// Simulate long running operation
Thread.Sleep(1000);
// Perform
Perform(ctx);
await ProcessAsync(listener);
}
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();
}
}
我使用 Apache Benchmark Tool 对此进行负载测试。当我发出 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();
}
}
【问题讨论】:
-
感谢您提供完整的解决方案。
-
@JonSkeet 需要对上述模式进行哪些修改才能使其服务于服务器发送事件,在这种情况下,响应流永远不会真正“关闭”。例如,我们如何使用它来“持续推送”数据到连接的客户端?
-
@CharlesO 我没有尝试过,但我假设如果你不在输出流上调用
output.Close();并且每次推送都刷新,它应该可以工作(当然,正确的标题上证所)。这也可能有所帮助:channel9.msdn.com/Events/TechDays/Techdays-2012-the-Netherlands/…
标签: c# .net http httplistener system.net