Skip to main content
 首页 » 编程设计

vb.net中如何限制并发异步网络请求

2024年09月07日22落叶

我经常需要发出大量网络请求,而又不会造成网络重载

我目前通过并行运行同步请求来实现此目的,利用 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 将不允许这些事件待处理。