我通过异步发出http get请求来验证图片网址。所有工作都可以正常使用下面的代码,但是当我有这么多图片时,我们的防火墙将阻止我的互联网访问,因为有很多线程同时请求。因此,我一直在寻找一种解决方案,如何限制并发运行线程的数量。我结束了这个thread告诉我使用SemaphoreSlim,但我不知道怎么能得到这个想法以及如何实现它?
如果这不是最好的方法,请建议一个更好的方法。我不确定使用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
答案 0 :(得分:4)
我们的防火墙将阻止我的互联网访问,因为有很多线程同时请求。因此,我一直在寻找一种解决方案,如何限制并发运行线程的数量。
非常确定防火墙限制了连接数,因此您希望限制连接数(不是线程)
是SemaphoreSlim等待还是等待Asnyc(无论如何有什么区别?)
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
答案 1 :(得分:0)
您可以像这样使用Task
和SemaphoreSlim
:
var MaxAllowedConcurrentRequestsCount = 20;
var guard = new SemaphoreSlim(0, MaxAllowedConcurrentRequestsCount);
foreach(var imageUrl in imageUrls)
{
guard.Wait()
var image = await Task.Factory.StartNew((imageUrl) => return myHttpClient.Get(imageUrl));
guard.Release();
// You can do whaterver you like with image. For example add it to you concurrent list.
}
答案 2 :(得分:-1)
我假设您不在WPF或Windows Form Thread中。如果您在await
之后只有一个线程正在工作。
由于我们假设您不在这些线程中,ThreadPool
用于执行await
之后的延续。您可以使用ThreadPool.SetMaxThreads
更改池使用的线程数量,但我建议您不要这样做,并将其留给.NET来做正确的事情。这通常是最好的方式。