4

我正在 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 任务将作为延续附加到它。
这会产生这样的日志:
Task Timeoud!超时时间:10000 毫秒,经过时间:3371 毫秒
我有异常记录等,可以确认没有异常和错误。似乎只是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,但在开始之前似乎有很大的延迟_GetAvailabilityswElapsed开始)。
所以我发现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 多个任务)。

4

1 回答 1

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)

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

于 2013-08-30T09:24:33.180 回答