[RESOLVED] Seeking advice: BackGroundWorker or Task
Presently I'm using BackGroundWorker(s) to do calculations which may take a long time (calculating a BackGroundImage, calculating the next simulation-step for objects ...). The result of each BGW is used whenever ready (i.e. if the information is used before ready/updated the older information is used).
Should I better use Tasks in such a scenario?
I far as I understand the documentation, I would expect a better performance using Tasks.
I did some experimentation, however I can't seem to find the correct implementation in order to let the main process (the GUI) continue with waiting the Tasks to complete. Do I realy have to use the .Wait Method in order to get any result from my Task? Isn't there a way to get the results of a Task without .Wait (like an Event TaskCompleted)?
Re: Seeking advice: BackGroundWorker or Task
I've never done it myself but I believe that you can call ContinueWith on the Task and pass TaskContinuationOptions.ExecuteSynchronously as an argument. The continuation action will then be executed synchronously, i.e. on the UI thread, when the original asynchronous task has completed. That's much like the RunWorkerCompleted event handler of a BackgroundWorker.
That said, if you're running this code inside a form then I'd stick to the BackgroundWorker. If it's in some other class that has no direct dependence on a UI then I'd switch to the TPL.
Re: Seeking advice: BackGroundWorker or Task
I should stipulate that you don't have to wait until the original task has completed to call ContinueWith. You call ContinueWith when you create the Task and it then stores the provided delegate in the Task object, to be invoked implicitly when the task completes.
Re: Seeking advice: BackGroundWorker or Task
Quote:
Originally Posted by
jmcilhinney
I've never done it myself .....
I didn't expect such a statement from you.
Quote:
Originally Posted by
jmcilhinney
That said, if you're running this code inside a form then I'd stick to the BackgroundWorker. If it's in some other class that has no direct dependence on a UI then I'd switch to the TPL.
Yes, as of now I call those calculations (as BGW or Task) from the UI, so I'll stichk with BGW.
However, since I'm looking to completly seperate the "simulation" for presentation on the UI I will also look into .ContinueWith.
Thanks
Re: Seeking advice: BackGroundWorker or Task
Quote:
Originally Posted by
opus
I didn't expect such a statement from you.
I've done some cursory research into the TPL and have been meaning to do more for some time but haven't had a specific need yet so haven't got around to it.
Re: Seeking advice: BackGroundWorker or Task
Since you seem to have a value that changes over time, you may want to investigate the Reactive framework.
As to ContinuationOptions.ExecuteSynchronously, I'm not sure that's the one you want to use. As I recall, that continues on the same thread that the Task ran on. Instead, use TaskScheduler.FromCurrentSynchronizationContext to the scheduler parameter when on the UI thread (i.e. create the Task and attach the continuation at the same time, as jmc mentioned)
If you have any interest in unit testing, I would strongly advise putting your own abstraction between your application and whatever libraries you use to implement this. (Both TPL and Rx have good APIs, so if you don't need to decouple for testing purposes then coding directly against their APIs is fine, their ability to allow unit tests to control the threading sucks big time though.)
Re: Seeking advice: BackGroundWorker or Task
I've read on .ContinueWith, it sounds promissing, however what is the correct syntax??
I'm using
Code:
Dim ChartTask = Task.Factory.StartNew(Sub() ChartWorks()) 'Chatworks is the sub that does the work(set a new BackGroundImage to a control)
ChartTask.Wait 'Without thisOne I get no result
I found no correct way to place .ContinueWith. "ChartTask.ContinueWith(TaskContinuationOption.ExecutesSynchronously)" is not accepted?
Re: Seeking advice: BackGroundWorker or Task
You need to give it a continuation for it to continue with. This is where you're first seeing the very different nature of this style of programming. Your ChartWorks method needs to be split in two: one part that generates the image, another that updates the UI control. You then run the first part as a new task, and supply the second part as the continuation. You specify both things at the beginning, but the continuation won't run until the later.
Here's a very noddy example. Note that you can click the button multiple times, and you'll get multiple updates as each of the tasks completes. There is NO error handling, normally you should attach continuations for error events using the TaskContinuationOptions enumeration and/or check the state of the Task in the continuation.
vbnet Code:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Task.Factory.StartNew(AddressOf GenerateImage).ContinueWith(AddressOf UpdateBackground, TaskScheduler.FromCurrentSynchronizationContext())
End Sub
Private colors() As Color = {Color.Red, Color.Green, Color.Blue}
Private currentColorIndex As Integer = 0
Private Function GenerateImage() As Image
Dim index = currentColorIndex
currentColorIndex = currentColorIndex + 1
If currentColorIndex >= colors.Length Then
currentColorIndex = 0
End If
Dim image As New Bitmap(100, 100)
Dim g = Graphics.FromImage(image)
g.FillRectangle(New SolidBrush(colors(index)), New Rectangle(New Point(2, 2), New Size(96, 96)))
g.Flush()
Threading.Thread.Sleep(1000)
Return image
End Function
Private Sub UpdateBackground(imageTask As Task(Of Image))
Panel1.BackgroundImage = imageTask.Result
End Sub
End Class
Re: Seeking advice: BackGroundWorker or Task
Thank you very much.
I got it working now for the BackGroundImage, although I had to build in a blocking mechanism (because ChartWorks needs access to files, and if you try to repaint the Background to fast those files would be read by several ChartWork Tasks).
I'll do the same with my other routines, Thanks
Yes, looking at it that way it is the same technique as using the BGW