我正在尝试开始使用任务,但我想比较使用标准HttpWebRequest.BeginGetResponse时的速度差异。
根据我的发现,使用BeginGetResponse向example.com发送和完成100个请求需要大约600毫秒
然而,使用Await GetResponseAsync需要5倍。大约3000ms。在制作中,在扩大规模时,这对我来说真的很重要。我做错了什么,或者Await GetResponseAsync本身比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 :(得分:2)
是否等待GetResponseAsync本身比BeginGetResponse慢?
如果没有良好的Minimal, Complete, and Verifiable code example,很难解决您的具体表现问题。那说......
在我看来,你在这里比较苹果和橘子。首先,实施中存在重大差异。在BeginGetResponse()
版本中,您同时启动所有请求,因此假设Web服务器会容忍它,它们会并行完成。在GetResponseAsync()
版本中,您只需在上一个请求完成后发起新请求。
这种序列化必然会减慢一切。
除此之外,BeginGetResponse()
版本在IOCP线程池中执行其所有工作,而GetResponseAsync()
版本使用单个UI线程来处理I / O事件的完成。 UI线程是一个瓶颈,因为它一次只能做一件事,并且因为你必须等待它可以执行其他任务才能继续处理I / O完成(一个变种)关于“一次只能做一件事”的问题)。
除此之外,您还必须处理消息循环中涉及的延迟,该延迟使异步完成出列以在UI线程中执行。
当你使用它时,发现GetResponseAsync()
方法速度较慢,我一点都不会感到惊讶。
如果您希望获得更好的性能,则应该在异步调用中使用ConfigureAwait(false)
。当然,这假设您可以以其他方式最小化与UI线程的交互(例如,结果的处理实际上不需要直接发布回UI线程)。但这样做会告诉框架不要麻烦编组完成回UI线程。至少在您发布的代码中,这是安全的,因为您实际上没有与async
事件处理程序方法中的UI对象进行交互。
所有这一切,当我更改你的代码以便同时运行GetResponseAsync()
版本时,我发现至少在我测试过的网络服务器上,它的工作速度与{{1}一样快}版本。在两种情况下,它都能在10秒内完成100次迭代。
BeginGetResponse()
有可能使用速度更快的Web服务器,您可能会开始遇到UI线程作为瓶颈问题,但我会说主要区别可能只是两个实现在逻辑上甚至不是相同。