ho creato il seguente semplice HttpListener
per servire più richieste contemporaneamente (su .NET 4.5):semplice HtppListener Asynchronous Task-ritorno con async/attendono di spedizione alto carico
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();
}
}
io uso Apache Benchmark Strumento per caricare questo test. Quando faccio una richiesta 1, ottengo il tempo di attesa massimo per una richiesta di 1 secondo. Se faccio 10 richieste, ad esempio, il tempo di attesa massimo per una risposta arriva a 2 secondi.
Come cambieresti il mio codice precedente per renderlo il più efficiente possibile?
Modifica
Dopo @ di JonSkeet risposta, ho cambiato il codice, come di seguito. Inizialmente, ho provato a simulare una chiamata di blocco, ma credo che fosse il problema principale. Quindi, ho preso il suggerimento di @ JonSkeet e lo cambio in Task.Delay (1000). Ora, il codice sottostante dà max. tempo di attesa come ca. 1 sec per 10 richieste simultanee:
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();
}
}
Grazie per aver fornito una soluzione completa. –
@JonSkeet quale modifica sarebbe richiesta al modello sopra per consentirgli di servire ** Eventi inviati dal server **, nel qual caso il flusso di risposta non si "chiude" realmente. Ad esempio, come useremmo questo per inviare dati "** continuous push **" ai client connessi? –
@CharlesO Non l'ho provato ma presumo che se non chiami 'output.Close();' sul flusso di output e Flush per ogni push, dovrebbe funzionare (ovviamente, con le intestazioni giuste in atto per SSE). Questo può aiutare anche: http://channel9.msdn.com/Events/TechDays/Techdays-2012-the-Public/2287 – tugberk