2016-08-09 13 views
1

Ich versuche, Aufgaben zu verwenden, aber ich wollte die Geschwindigkeitsdifferenz vergleichen, wenn Sie eine Standard-HttpWebRequest.BeginGetResponse verwenden.VB.Net BeginGetResponse viel schneller als die Verwendung von GetResponseAsync?

Von dem, was ich gefunden habe, ist es unter ~ 600 ms und BeginGetResponse

jedoch mit zu example.com 100 Anfragen vervollständigen zu senden, mit Await GetResponseAsync ist 5-fach, dass die Einnahme. Etwa 3000ms. In der Produktion ist mir das wichtig, wenn ich es hochskaliere. Mache ich etwas falsch, oder ist GetResponseAsync von Natur aus langsamer als BeginGetResponse?

Imports System.Net 

Public Class Form1 
    Private sw As New Stopwatch 
    Private respCounter As Integer 
    Private iterations As Integer = 100 

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
     sw.Start() 

     For i = 1 To iterations 
      Dim req As HttpWebRequest = HttpWebRequest.Create("http://example.com") 
      Dim state As New RequestState 
      state.req = req 
      req.BeginGetResponse(AddressOf respCallback, state) 
     Next 
    End Sub 

    Private Sub respCallback(ar As IAsyncResult) 
     Dim state As RequestState = ar.AsyncState 
     state.resp = state.req.EndGetResponse(ar) 
     state.respStream = state.resp.GetResponseStream 
     state.respStream.BeginRead(state.buffer, 0, 1024, AddressOf readCallback, state) 
    End Sub 

    Private Sub readCallback(ar As IAsyncResult) 
     Dim state As RequestState = ar.AsyncState 
     Dim read As Integer = state.respStream.EndRead(ar) 
     If read > 0 Then 
      state.respBody += System.Text.ASCIIEncoding.ASCII.GetString(state.buffer, 0, read) 
      state.respStream.BeginRead(state.buffer, 0, 1024, AddressOf readCallback, state) 
     Else 
      state.Dispose() 
      respCounter += 1 
      If respCounter = iterations Then 
       respCounter = 0 
       sw.Stop() 
       Debug.WriteLine(sw.ElapsedMilliseconds) 
       sw.Reset() 
      End If 
     End If 
    End Sub 

    Private Async Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click 
     sw.Start() 

     For i = 1 To iterations 
      Dim req As HttpWebRequest = HttpWebRequest.Create("http://example.com") 
      Using resp As WebResponse = Await req.GetResponseAsync 
       Using sr As New IO.StreamReader(resp.GetResponseStream) 
        Dim respBody As String = Await sr.ReadToEndAsync 
       End Using 
      End Using 
      respCounter += 1 
      If respCounter = iterations Then 
       respCounter = 0 
       sw.Stop() 
       Debug.WriteLine(sw.ElapsedMilliseconds) 
       sw.Reset() 
      End If 
     Next 

     MsgBox("Execution!") 
    End Sub 

End Class 

Public Class RequestState 
    Implements IDisposable 

    Public req As HttpWebRequest 
    Public resp As HttpWebResponse 
    Public respStream As IO.Stream 
    Public buffer(1024) As Byte 
    Public respBody As String 

#Region "IDisposable Support" 
    Private disposedValue As Boolean ' To detect redundant calls 

    ' IDisposable 
    Protected Overridable Sub Dispose(disposing As Boolean) 
     If Not disposedValue Then 
      If disposing Then 
       ' TODO: dispose managed state (managed objects). 
       respStream.Close() 
       respStream.Dispose() 
       resp.Close() 
      End If 

      ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below. 
      ' TODO: set large fields to null. 
     End If 
     disposedValue = True 
    End Sub 

    ' TODO: override Finalize() only if Dispose(disposing As Boolean) above has code to free unmanaged resources. 
    'Protected Overrides Sub Finalize() 
    ' ' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above. 
    ' Dispose(False) 
    ' MyBase.Finalize() 
    'End Sub 

    ' This code added by Visual Basic to correctly implement the disposable pattern. 
    Public Sub Dispose() Implements IDisposable.Dispose 
     ' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above. 
     Dispose(True) 
     ' TODO: uncomment the following line if Finalize() is overridden above. 
     ' GC.SuppressFinalize(Me) 
    End Sub 
#End Region 
End Class 
+0

@x ... Hi, ich habe Anrufe zu EndGetResponseStream und EndGetResponse hinzugefügt, wenn die Anfragen abgeschlossen sind. Dann bekomme ich eine kryptische Ausnahme "Zusätzliche Information: Das IAsyncResult-Objekt wurde nicht von der entsprechenden asynchronen Methode für diese Klasse zurückgegeben." –

+1

Ich mache nur einen Test mit GetResponse() und GetResponseAsync() und BeginGetResponse/EndGetResponse, sie zeigen die gleiche Zeit. –

Antwort

2

ist Await GetResponseAsync von Natur aus langsamer als BeginGetResponse?

Es ist schwierig, Ihre spezifischen Leistungsbedenken ohne eine gute Minimal, Complete, and Verifiable code example zu adressieren. Das sagte & hellip;

Es scheint mir, dass Sie hier Äpfel und Orangen vergleichen. In erster Linie gibt es einen großen Unterschied in den Implementierungen. In Ihrer Version BeginGetResponse() initiieren Sie alle Anfragen gleichzeitig. Wenn Sie also davon ausgehen, dass der Webserver sie toleriert, werden sie parallel ausgeführt. In Ihrer Version GetResponseAsync() initiieren Sie nur eine neue Anfrage, nachdem die vorherige abgeschlossen wurde.

Diese Serialisierung verlangsamt notwendigerweise alles.

Darüber hinaus führt die BeginGetResponse()-Version alle ihre Arbeit im IOCP-Thread-Pool aus, während die GetResponseAsync()-Version den einzelnen UI-Thread für die Vervollständigung von E/A-Ereignissen verwendet. Der UI-Thread ist ein Flaschenhals, da er immer nur eine Sache gleichzeitig ausführen kann und weil er warten muss, bis er verfügbar ist, bevor er mit den E/A-Vervollständigungen (einer Variante) fortfahren kann auf der "kann nur eine Sache zu einer Zeit" Problem).

Darüber hinaus müssen Sie sich auch mit der Latenz der Nachrichtenschleife befassen, die die asynchronen Vervollständigungen für die Ausführung im UI-Thread entfernt.

Es würde mich überhaupt nicht überraschen zu finden, dass der GetResponseAsync() Ansatz ist langsamer, wenn in der Art, wie Sie es verwenden.

Wenn Sie eine bessere Leistung wünschen, sollten Sie wahrscheinlich ConfigureAwait(false) in Ihren asynchronen Anrufen verwenden. Dies setzt natürlich voraus, dass Sie die Interaktion mit dem UI-Thread anderweitig minimieren können (z. B. muss die Verarbeitung der Ergebnisse nicht direkt in den UI-Thread zurückgeschrieben werden). Wenn Sie dies jedoch tun, wird das Framework angewiesen, die Abarbeitung von Komplettierungen nicht mehr an den UI-Thread zu erinnern. Zumindest in dem von Ihnen geposteten Code wäre dies sicher, da Sie nicht mit UI-Objekten in der Ereignishandlermethode async interagieren.

Alles, was gesagt, wenn ich den Code geändert, so dass es die GetResponseAsync() Version gleichzeitig laufen würde, fand ich, dass zumindest mit dem Web-Server ich getestet, es ist nur so schnell wie die BeginGetResponse() Version gearbeitet. Es war in der Lage, 100 Iterationen in etwas mehr als 10 Sekunden in beiden Fällen abzuschließen.

Private Async Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click 
    sw.Start() 

    Dim tasks As List(Of Task(Of String)) = New List(Of Task(Of String)) 

    For i = 1 To iterations 
     Dim req As HttpWebRequest = HttpWebRequest.Create("http://example.com/") 

     tasks.Add(ReadResponse(req)) 
    Next 

    Await Task.WhenAll(tasks) 

    sw.Stop() 
    Debug.WriteLine(sw.ElapsedMilliseconds) 
    sw.Reset() 
    MsgBox("Execution!") 
End Sub 

Private Async Function ReadResponse(req As HttpWebRequest) As Task(Of String) 
    Using resp As WebResponse = Await req.GetResponseAsync 
     Using sr As New IO.StreamReader(resp.GetResponseStream) 
      Dim respBody As String = Await sr.ReadToEndAsync 

      Return respBody 
     End Using 
    End Using 
End Function 

Es ist möglich, mit einem schnelleren Web-Server, können Sie beginnen in die UI-Thread-as-a-Engpass Problem zu laufen, aber ich würde sagen, dass der Hauptunterschied nur wahrscheinlich ist, dass die beiden Implementierungen wirklich ‚aren t sogar logisch gleich.

+0

Ok, danke für die langwierige Antwort, ich werde dies als die Antwort markieren, weil ich ziemlich sicher bin, dass dies die Erklärung ist, nach der ich gesucht habe. Danke, einige dieser Dinge, über die ich weitere Nachforschungen anstellen muss (ja, ich bin ein Noob). Ich werde auch den ConfigureAwait (false) -Tipp ausprobieren. –

+1

Bei näherer Betrachtung bemerkte ich ein wichtiges Detail, das ich zuvor übersehen hatte. Bitte sehen Sie meine aktualisierte Antwort. –

Verwandte Themen