I am starting a new task in vb.net and waiting a while. If by that time the task is not completed, I will not attach another task as a continuation, and inside this other task log, the time for executing the task has come out1. The code looks something like this:
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
For some reason, task.Wait(timeout) does not wait for this specific time and simply skips it. Since the task was not completed at that time, the LogAvailabilityTimeout task will be attached to it as a continuation.
The result is a log like this:
Task Time! Standby time: 10000 ms , Elapsed time: 3371ms
I have exception logging, etc., and I can confirm the absence of exceptions and errors. It just seems like task.Wait(timeout) randomly decides not to wait ...
Has anyone come before this? Are there any solutions? Thank you for your time.
---- EDIT ----
Ok, so I did an experiment by adding a stopwatch and outputting material for debugging:
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 looks something like this:
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
It seems like it really waits for 10,000, but there seems to be a big delay before starting _GetAvailability starts (swElapsed).
Therefore, I found that TaskFactory.StartNew() does not always start the task immediately, if the thread pool is full, the task will be queued. Although this is understandable, Task.Wait() does not explicitly take this into account, so the task may begin after the wait completes. I am reading about TaskScheduler now to check if I can increase the thread pool to fit all tasks, or do something else to solve the problem (but I have no idea what at the moment hehe) ... If do you have any ideas, let me know :)
---- EDIT ----
Another update for you ladies and gentlemen. The problem of filling the thread pool was solved (initially), hinting at creating a new task using TaskCreationOptions.LongRunning . This, according to MS documentation, tells TaskScheduler that this task can block the thread pool for a longer period, in which case the scheduler creates an additional thread to host it. This is how I run tasks now:
Dim task As Task(Of Availability) = task.Factory.StartNew( Function() As Availability Return _GetAvailability(requests) End Function, TaskCreationOptions.LongRunning) task.Wait(timeout)
Since this change, all tasks seem to be executed as they are started (not placed in the queue). This happens in tests when I run about 50 tasks. Now I'm moving on to more stressful testing (1000+ tasks).