Task.Wait不等待

时间:2013-08-30 08:03:36

标签: .net vb.net multithreading task-parallel-library

我在vb.net中开始一项新任务并等待一段时间。如果到那时任务没有完成,我不想附加另一个任务作为继续,并且在另一个任务日志内部延长了task1的执行时间。代码看起来或多或少:

Dim task As Task(Of Availability) = task.Factory.StartNew(
                                         Function() As Availability
                                             Return _GetAvailability(requests)
                                         End Function)
task.Wait(timeout)

If task.IsCompleted Then
    MyBase.availability = task.Result
Else
    task.ContinueWith(Sub(previous)
                         LogAvailabilityTimeout(timeout, elapsedTime)
                      End Sub, TaskContinuationOptions.OnlyOnRanToCompletion)
End If

由于某种原因偶尔task.Wait(timeout)不会等到那个特定的时间而只是跳过。由于当时没有任务完成任务,因此LogAvailabilityTimeout任务将作为continuation附加到它。
这导致如下日志:
任务Timeoud!超时时间: 10000ms ,经过时间: 3371ms
我有异常日志记录等,可以确认没有异常,也没有错误。看来task.Wait(timeout)随机决定不等待...... 以前有人来过这个吗?有什么解决方案吗?谢谢你的时间。

----编辑----

好的,所以我做了一个实验,添加一个秒表并输出调试内容:

Dim swTemp As StopWatch = StopWatch.StartNew()
Dim task As Task(Of Availability) = task.Factory.StartNew(
                                         Function() As Availability
                                             Return _GetAvailability(requests)
                                         End Function)
task.Wait(timeout)

swTemp.Stop()
Debug.WriteLine("Waited For: " & swTemp.ElapsedMilliseconds)

If task.IsCompleted Then
    MyBase.availability = task.Result
Else
    task.ContinueWith(Sub(previous)
                         LogAvailabilityTimeout(timeout, elapsedTime)
                      End Sub, TaskContinuationOptions.OnlyOnRanToCompletion)
End If

_GetAvailability或多或少看起来像这样:

Private Function _GetAvailability(requests As RequestsCollection) As Availability
    Dim swElapsed As New StopWatch = StopWatch.StartNew()
    'do some stuff here (CPU heavy and network related)
    swElapsed.Stop()
    Debug.WriteLine("Elapsed: " & swElapsed.ElapsedMilliseconds)
    Me.elapsedTime = swElapsed.ElapsedMilliseconds
    Return xxx
End Function

似乎确实在等待10000,但在_GetAvailability开始内部( swElapsed 开始)之前似乎有很大的延迟。
所以我发现TaskFactory.StartNew()并不总是立即启动任务,如果线程池变满,任务将被放入队列中。虽然这是可以理解的,但Task.Wait()显然没有考虑到这一点,因此任务可能在等待完成后开始。我正在阅读有关TaskScheduler的内容,以检查我是否可以增加线程池以适应所有任务,或者做一些其他事情来解决问题(但我不知道现在是什么嘿)...如果你们有任何想法让我们我知道:)

----编辑----

女士和天才的另一个更新。通过用TaskCreationOptions.LongRunning暗示新任务创建(最初)解决了线程池填满的问题。这根据MS文档提示TaskScheduler,该任务可能会阻塞线程池更长的时间,在这种情况下,调度程序创建一个额外的线程来容纳它。这就是我现在解雇任务的方式:

Dim task As Task(Of Availability) = task.Factory.StartNew(
                                         Function() As Availability
                                             Return _GetAvailability(requests)
                                         End Function, TaskCreationOptions.LongRunning)
task.Wait(timeout)

由于此更改,所有任务似乎都在启动时执行(不会被放入队列)。当我开始执行大约50个任务时,这是在测试中。我现在正在进行更多负载测试(1000多个任务)。

1 个答案:

答案 0 :(得分:1)

您可以按如下方式更改您的功能:

Private Function _GetAvailability(requests As RequestsCollection) As Tuple(Of Availability, Long)
    Dim swElapsed As New StopWatch = StopWatch.StartNew()
    'do some stuff here (CPU heavy and network related)
    swElapsed.Stop()
    Debug.WriteLine("Elapsed: " & swElapsed.ElapsedMilliseconds)
    Return Tuple.Create(xxx,swElapsed.ElapsedMilliseconds)
End Function

然后总是附加你的延续方法:

task.ContinueWith(Sub(previous)
    If previous.Item2 > timeout
         LogAvailabilityTimeout(timeout, previous.Item2)
    End If
End Sub, TaskContinuationOptions.OnlyOnRanToCompletion)

哪个至少应该解决您的报告问题。