Vb.net 当我使用";时,如何控制线程数;任务。WhenAll“;
我通过异步发出http get请求来验证图像URL。下面的代码都可以正常工作,但当我有这么多图像时,我们的防火墙会阻止我的互联网访问,因为有这么多线程同时请求。因此,我正在寻找一种解决方案,来限制并发运行线程的数量。最后,我告诉我如何使用它,但不知何故,我无法得到这个想法以及如何实现它Vb.net 当我使用";时,如何控制线程数;任务。WhenAll“;,vb.net,multithreading,async-await,semaphore,Vb.net,Multithreading,Async Await,Semaphore,我通过异步发出http get请求来验证图像URL。下面的代码都可以正常工作,但当我有这么多图像时,我们的防火墙会阻止我的互联网访问,因为有这么多线程同时请求。因此,我正在寻找一种解决方案,来限制并发运行线程的数量。最后,我告诉我如何使用它,但不知何故,我无法得到这个想法以及如何实现它 添加任务时,信号量lim wait或waitAsnyc(到底有什么区别?)应该在foreach中吗?我可以像在代码中那样使用linq创建任务列表吗? 为什么要使用task.Run 执行哪一行之后线程开始?在t
- 添加任务时,信号量lim wait或waitAsnyc(到底有什么区别?)应该在foreach中吗?我可以像在代码中那样使用linq创建任务列表吗?
- 为什么要使用task.Run李>
- 执行哪一行之后线程开始?在task.run或task.whalll之后
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
我假设您不在WPF或Windows窗体线程中。如果是,则在
等待
之后将只有一个线程工作
由于我们假设您不在这些线程中,因此在
等待
之后,将使用执行continuations。您可以使用更改池使用的线程数量,但我建议您不要这样做,而是让.NET来做正确的事情。这通常是最好的方法。您可以像这样使用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.
}
我们的防火墙将阻止我的internet访问,因为有太多线程同时请求。因此,我正在寻找一种解决方案,来限制并发运行线程的数量
可以肯定的是,防火墙限制了你的连接数,因此你想要限制你的连接数(而不是线程数)
信号量是lim wait还是waitAsnyc(到底有什么区别?)
Wait
是一种同步等待-它阻止调用线程WaitAsync
是一种异步等待-它释放调用线程,并在信号量可用时继续执行当前方法
添加任务时是否应在foreach中?我可以像在代码中那样使用linq创建任务列表吗
您可以通过以下两种方式完成:显式构建列表,或者使用LINQ
为什么要使用task.Run
那是答案中的一个错误<代码>任务。这里当然不需要或不需要运行
执行哪一行之后线程开始?在task.run或task.whalll之后
当您调用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
我会继续等待他们,或者用一个简单的老办法。当然还有一个更优雅的解决方案。为什么不使用Parallel.ForEach设置MaxDegreeOfParallelism呢?事实上,下面的帖子建议我使用更好的方法,我确实尝试了这两种方法,但我用这段代码比Parallel.ForEach获得了更好的性能。我查过那篇文章。不使用Parallel.ForEach是聪明的。我根据你的想法发布了一个答案。查看..限制线程数是自定义TaskScheduler的任务,如中的QueuedTaskScheduler。其他任何东西都只是浪费线程池线程。不过,更好的选择是使用具有特定MaxDegreeOfParallelism的ActionBlock。它简单得多,允许您简单地将所有URL发布到一个队列中进行处理。实际上,我是在WPF的ViewModel中这样做的。你所说的“如果你在等待之后只有一个线程在工作”是什么意思?你的意思是它不是多线程?如果没有,为什么我会看到速度增加?它运行速度非常快。如果您在WPF线程中,wait必须与WPF
调度程序同步。基本上,它会使用dispatcher.Invoke
在dispatcher中将延续注册为操作。OP希望同时执行多个GET以降低速度,但不超过防火墙设置的限制。这与WPF或wait
@batmaci之后的线程无关,绝对不是。基本上,并发请求意味着同时建立到主机的多个连接。这些连接可以由同一个线程维护。因此,如果您在收到第一个请求的答案并关闭第一个连接之前打开第二个连接(并从主机请求某些内容),就会发生并发请求。@batmaci您低估了您编写示例时连接打开的速度,初始调用线程会逐个打开每个连接。一旦通信完成,线程池线程将在等待myHttpClient.GetAsync(myImageurl)
之后处理所有事情。然而,即使您的连接只打开了几毫秒,打开连接的第一个线程也会更快。@batmaci您可以查看下面的链接,该链接描述了在某些情况下为什么使用loop和ContinueWith而不是async/WAIT。来自@Panagiotis Kanavos的评论发生了什么。他提到了你的方法的一个缺点。我在比较你的建议和他的建议。现在我看到他删除了他的评论。您的方法和使用QueuedTaskScheduler之间有什么大的区别吗?这也很好。我喜欢它,因为它使用了平行。我认为很酷。我的代码是以较低的级别编写的,因此您可以看到算法。@batmaci在与Stephen聊了一会儿之后,我刚刚在调用循环中使用了Wait而不是ContinueWith。为什么使用task.factory代替task.whenall?在foreach之前或在foreach内部初始化guard会有什么不同吗?将异步获取图像的逻辑与控制分离不是更好吗