我经常需要发出大量网络请求,而又不会造成网络重载
我目前通过并行运行同步请求来实现此目的,利用 ThreadPool.SetMinThreads 和 MaxDegreeOfParallelism 来准确指定同时运行的请求数
现在效果很好,但感觉不对。
我真的很想利用异步方法,但我不知道如何限制并发请求的数量。
我并行执行此操作的方法的简化示例(使用网络客户端,为了简洁起见,没有错误处理):
Private Function SearchSitesForKeywordInParallel(ByVal keyword As String, ByVal sites As String(), ByVal maxConcurrency As Integer) As String()
Dim po As New ParallelOptions
po.MaxDegreeOfParallelism = maxConcurrency
Threading.ThreadPool.SetMinThreads(maxConcurrency, 2)
Dim sitesContainingKeyword As New Concurrent.ConcurrentBag(Of String)
Parallel.For(0, sites.Count, po, Sub(i)
Dim wc As New Net.WebClient
wc.Proxy = Nothing
Dim pageSource As String = wc.DownloadString(sites(i))
If pageSource.Contains(keyword) Then
sitesContainingKeyword.Add(sites(i))
End If
End Sub)
Return sitesContainingKeyword.ToArray
End Function
这是一个阻塞函数,这正是我所需要的。 现在我已经在常规 for 循环中测试了 webclient.downloadStringAsync 方法,它几乎会立即触发所有请求,从而导致网络过载。
我想做的是最初发出X个请求,然后在每个响应返回时发出新的请求。
我相当确定任务是可行的方法,并且我肯定已经阅读了一些非常好的 C# 实现,但我的 C# 经验有限,而且我很难将 C# lambda 转换为 vb.net。
我也仅限于 vs2010 和 .net4,因此 .net4.5 async wait 的优点对我来说不是一个选择。
非常感谢任何帮助
请您参考如下方法:
不确定,如果我完全理解,你到底想要实现什么,但是如果你想使用 aync 方法,你可以这样做:
Dim google As String = "http://www.google.com/#&q="
Dim qsites As New Concurrent.ConcurrentQueue(Of String)
For Each k In {"foo", "bar", "john", "jack", "stackoverflow", "basic", "ship", "car", "42"}
qsites.Enqueue(google & k)
Next
Dim cde As New System.Threading.CountdownEvent(qsites.Count)
Dim strings As New Concurrent.ConcurrentBag(Of String)
Dim completedhandler = Sub(wco As Object, ev As Net.DownloadStringCompletedEventArgs)
Dim wc = DirectCast(wco, Net.WebClient)
Debug.Print("got one!")
strings.Add(ev.Result)
cde.Signal()
Dim s As String = String.Empty
If qsites.TryDequeue(s) Then
Debug.Print("downloading from {0}", s)
wc.DownloadStringAsync(New Uri(s))
End If
End Sub
Dim numthreads As Integer = 4
System.Threading.Tasks.Task.Factory.StartNew(Sub()
For i = 1 To numthreads
Dim s As String = String.Empty
If qsites.TryDequeue(s) Then
Dim wc As New Net.WebClient
wc.Proxy = Nothing
AddHandler wc.DownloadStringCompleted, completedhandler
Debug.Print("downloading from {0}", s)
wc.DownloadStringAsync(New Uri(s))
End If
Next
End Sub)
cde.Wait()
您只需要在不同的线程/任务中“启动”异步下载,因为(据我所知)WC 的 downloadcompleted 事件在 UI 线程(或 currentsync..context)中触发,并且 cde.wait 将不允许这些事件待处理。