使用“Task.WhenAll”时如何控制线程数

bat*_*aci 2 vb.net multithreading semaphore async-await

我正在通过异步发出 http get 请求来验证图像 url。使用下面的代码一切正常,但是当我有这么多图像时,我们的防火墙将阻止我的互联网访问,因为同时请求的线程太多。因此,我正在寻找如何限制并发运行线程数的解决方案。我结束了这个线程告诉我使用 SemaphoreSlim但不知何故我无法理解这个想法以及如何实现它?

  • 在添加任务时,SemaphoreSlim wait 或 waitAsnyc(有什么区别?)应该在 foreach 内?我可以像在代码中一样使用 linq 创建任务列表吗?
    • 为什么要使用task.Run?
    • 线程在哪一行执行之后开始?在 task.run 或 task.whenall 之后?

如果这不是最好的方法,请提出更好的方法。我不确定将 MaxDegreeOfParallelism 与 parallel.foreach 一起使用是否也有意义?

  Dim tasks = myImages.Select(Function(x) testUrl_async(x))
  Dim results = Await Task.WhenAll(tasks)

Async Function testUrl_async(ByVal myImage  As image) As Task(Of image)
   Dim myImageurl as string=myImage.imageurl
   myHttpResponse = Await myHttpClient.GetAsync(myImageurl)
    If myHttpResponse.IsSuccessStatusCode Then
        Return myImage
    Else
        Return Nothing
    End If
End Function
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 5

由于并发请求的线程太多,我们的防火墙将阻止我的 Internet 访问。因此,我正在寻找如何限制并发运行线程数的解决方案。

非常确定防火墙限制了您的连接数,因此您想限制连接数(而不是线程数)。

是 SemaphoreSlim wait 还是 waitAsnyc(有什么区别?)

Wait是一个同步等待 - 它阻塞调用线程。WaitAsync是一个异步等待 - 它释放调用线程并在信号量可用时恢复执行当前方法。

添加任务时应该在foreach内?我可以像在代码中一样使用 linq 创建任务列表吗?

您可以采用任何一种方式:显式构建列表,或使用 LINQ。

为什么要使用task.Run?

那是那个答案的错误。Task.Run这里当然不需要或不需要。

线程在哪一行执行之后开始?在 task.run 或 task.whenall 之后?

当您调用 时Task.Run,该委托会立即排队到线程池中。但是正如我上面所说,您不想使用Task.Run(也不应该在原始答案中使用它)。


所以,这样的事情就足够了:

Private _mutex As New SemaphoreSlim(20)
Async Function testUrl_async(myImage As image) As Task(Of image)
    Await _mutex.WaitAsync()
    Try
        Dim myImageurl = myImage.imageurl
        Dim myHttpResponse = Await myHttpClient.GetAsync(myImageurl)
        Return If(myHttpResponse.IsSuccessStatusCode, myImage, Nothing)
    Finally
        _mutex.Release()
    End Try
End Function
Run Code Online (Sandbox Code Playgroud)