0

I have a vb.net service that needs some threads to handle each function call separately and avoid time consumption.

I have 2 functions that needs to implement threads :

Before asking my questions, here's my two functions :

1- LaunchTasks() : If the task is well launched it calculates the 'NextRunDate' for this task otherwise it skips it.

'Dim oThread As Threading.Thread
For Each oRow As DataRow In oDatatable.Rows
    Dim oCLASSE_Task As New CLASSE_Task
    If oCLASSE_Task.Load(oRow.Item("Mytask")) Then

        'oThread = New Threading.Thread(AddressOf oTask.launchSteps)
        'oThread.Priority = Threading.ThreadPriority.Normal
        'oThread.Start()

        Dim oThread = System.Threading.Tasks.Task(Of Boolean).Factory.StartNew(Function() oCLASSE_Task.launchSteps())

    End If
Next
' Need to wait until all threads finish

2- calculateRunDates()

'It's called for each object in CLASSE_Task

'Dim oThread As Threading.Thread
For Each oRow As DataRow In oDatatable.Rows
    Dim oCLASSE_Task As New CLASSE_Task
    If oCLASSE_Task.Load(oRow.Item("Mytask")) Then

        Dim oThreadTask = System.Threading.Tasks.Task(Of Boolean).Factory.StartNew(Function() oCLASSE_Task.calculateNextRunDate())

        'oThread = New Threading.Thread(AddressOf oTask.calculateNextRunDate)
        'oThread.Priority = Threading.ThreadPriority.Normal
        'oThread.Start()

    End If
Next
' Need to wait until all threads finish

I always call LaunchTask() first and then calculateRunDates() (if I get new record in the database).

I must wait for all the threads in the function LaunchTask() to finish before I start the calculateRunDates().

  • How can I do this using TPL (I never used it before), something like thread.join()?

  • Should I use threads or TPL in this situation?

  • How Can I handle exception using TPL, in a service (somthing like that)?

Note: I have locks in my CLASSE_Task using SyncLock.

There is not enough examples using vb.net, mostly C#.

Hope that I was clear enough.

Community
  • 1
  • 1
billybob
  • 2,859
  • 6
  • 35
  • 55

2 Answers2

2

First, to answer your questions:

How can I do this using TPL (I never used it before), something like thread.join()?

You should use task.Wait() for that. If you wanted to wait for several Tasks, you can use Task.WaitAll().

Should I use threads or TPL in this situation?

You should use TPL. It's easier to use and more efficient.

How can I handle exception using TPL, in a service?

If the code inside a Task throws an exception and you then Wait() on that Task (or WaitAll() on multiple Tasks), it will throw AggregateException containing the thrown exception. If you don't call Wait(), you can use ContinueWith(), as the question you linked to suggests.


But with your code, I think a better choice would be to use Parallel.ForEach(): it will take care of creating the Tasks for you, it will do it more efficiently (it shares Tasks between iterations) and you don't have to handle waiting, because when it returns, all iteration is complete:

Parallel.ForEach(oDatatable.Rows.Cast(Of DataRow)(),
                 Sub(oRow)
                     Dim oCLASSE_Task As New CLASSE_Task
                     If oCLASSE_Task.Load(oRow.Item("Mytask")) Then
                         oCLASSE_Task.launchSteps()
                     End If
                 End Sub)
svick
  • 236,525
  • 50
  • 385
  • 514
  • Thanks, I will try to run and test my program with following code ! – billybob Aug 13 '12 at 19:23
  • Sometimes, it jumps over some records. Some records are not updated or not recorded. Do you have any idea ? I can't even debug. There is a way to debug ? – billybob Aug 13 '12 at 20:15
  • You should be able to debug normally. Breakpoints should work just fine. – svick Aug 13 '12 at 20:27
  • In fact, when I use breakpoints, it breaks and the records are saved correctly. But when I do not put Breakpoints, it just jumps over some functions inside the launchSteps() or calculateNextRunDate() and records are not saved in the database. There is a something that I must add to handle database records ? – billybob Aug 14 '12 at 12:44
1

To wait for completion of multiple task you can use Task.WaitAll(...) method. See this for an example. The article also shows how to handle exceptions if any were thrown by the tasks. Put try/catch around Task.WaitAll() and inspect the caught AggregateException to get individual exceptions thrown by the tasks.

However, it looks like your code would benefint from using Parallel.ForEach API, which will provide more intelligent loop partition. Simply creating a separate Task for each row may overload the thread pool.

Volma
  • 1,305
  • 9
  • 17
  • What Parallel.ForEach will do for you, it will try to create optimal number of concurrent Tasks to work on the loop. This number will be close to the number of CPU cores on your machine. This is better than just creating one Task per each DataRow, because it reduces context switches and doesn't create much more threads than can possibly run concurrently on your machine. – Volma Aug 13 '12 at 19:08
  • Ok, I understand. I will use Parallel.ForEach(), it seems better for my case. – billybob Aug 13 '12 at 19:14
  • @Volma Using many `Task`s most likely won't create many threads, so it won't cause context switches. But you are right that it is less efficient than using `Parallel.ForEach()`. – svick Aug 13 '12 at 19:18
  • @svick Why not? The number of threads and the rate of their creation will be controlled by the thread pool, but it will most likelly be much larger than with Parallel.ForEach() – Volma Aug 13 '12 at 19:39
  • @Volma Not really. With `Parallel.ForEach()`, the number of threads used is also controlled by the `ThreadPool` (unless you explicitly set a maximum), so the same rules apply. – svick Aug 13 '12 at 19:53
  • ForEach contains additional logic on top of ThreadPool throttling as far as I know. See this for example: [link] http://stackoverflow.com/questions/1114317/does-parallel-foreach-limits-the-number-of-active-threads – Volma Aug 13 '12 at 20:41