I know that there is no need to wait for a Parallel.For but since UI Windows messages (WinForms message pump) are being processed during the Parallel.For I would like to wait for Parallel.For to finish.
Is it a good idea to encapsulate a Parallel.For inside a Task, then wait for it? Is there any better approach?
Thanks.
CancellationTokenSource token = new CancellationTokenSource();
const int len = 100;
double[] array = new double[len];
Task t = Task.Factory.StartNew(delegate {
Parallel.For(0, len, delegate(int i, ParallelLoopState loopState) {
array[i] += 1;
});
try
{
t.Wait(token.Token);
}
catch (OperationCanceledException e)
{
rc = false;
}
Instead of Parallel.For why not use just Task and call Task.WaitAll()?
var t1 = Task.Run(() => {});
var t2 = Task.Run(() => {});
Task.WaitAll(t1, t2);
If you want to wait for a Parallel.For() to finish, you simply don't start it in a separate task!
Parallel.For() doesn't return until it has completed (even if it uses multiple threads to do the work).
Note that Parallel.For() returns a ParallelLoopResult - it does not return a task or anything else which would allow you to wait for it to finish, so if it did return before it was complete (as you are asserting) there would be no way to know when it had finished.
What makes you be so confident that WM_PAINT and other Windows messages are pumped while Parallel.For or Task.Wait is blocking on the UI thread?
The following simple example proves you're wrong. The form is not getting repainted to red for the whole 15 seconds, while Parallel.For is working.
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinFroms_21681229
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
this.Shown += MainForm_Shown;
}
void MainForm_Shown(object sender, EventArgs e)
{
MessageBox.Show("Before");
this.BackColor = Color.FromName("red");
this.Invalidate();
// the form is not getting red for another 15 seconds
var array = new double[] { 1, 2, 3 };
Parallel.For(0, array.Length, (i) =>
{
System.Threading.Thread.Sleep(5000);
Debug.Print("data: " + array[i]);
});
MessageBox.Show("After");
}
}
}
Here is how to run the tasks in parallel, while keeping the UI responsive:
async void MainForm_Shown(object sender, EventArgs e)
{
MessageBox.Show("Before");
this.BackColor = Color.FromName("red");
this.Invalidate();
// the form is not getting red for another 15 seconds
var array = new double[] { 1, 2, 4 };
var tasks = array.Select((n) => Task.Run(()=>
{
Thread.Sleep(5000);
Debug.Print("data: " + n);
}));
await Task.WhenAll(tasks);
MessageBox.Show("After");
}
You could have done something like await Task.Factory.StartNew(() => Parallel.For(...)), but that would use at least one more thread than really needed.
To understand what's going on behind the scene here, you'd need to understand how WinForms message loop works inside Application.Run, how await yields the execution control back to the message loop and then gets continued via WindowsFormsSynchronizationContext, when the task has completed. The async-await tag wiki could help, it contains links to some great, must-read resources.
If you're interested to know how message pumping works during blocking operations, check this answer.
Related
I think I am missing something here..
I expected the call to CountCharsAsync() to be non blocking. But it doesn't seem that way. When i click on my button nothing happens for the first five seconds.. and the UI gets stuck...
But the second version is fine.
Could someone explain the difference between these two ways...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AsyncAwaitExample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
textBox1.Text += "Count is : ";
int count = await CountCharsAsync();
textBox1.Text += count;
textBox1.Text += "\r\n-----------\r\n";
textBox1.Text += "Count is : ";
Task<int> tsk = new Task<int>(CountChars);
tsk.Start();
int count2 = await tsk;
textBox1.Text += count2;
}
private int CountChars()
{
int count = 50;
Thread.Sleep(5000);
return count;
}
private async Task<int> CountCharsAsync()
{
int count = 50;
Thread.Sleep(5000);
return count;
}
}
}
You're calling Thread.Sleep in your async method. That will block whatever thread it's running on... which is still going to be the UI thread. Calling an async method doesn't start a new thread by itself. Other threads can be involved depending on exactly what happens within the method, but until the first await expression, the method will execute synchronously on the same thread as the calling code... and your async method doesn't have any await expressions (which should already be giving you a warning).
You should use:
await Task.Delay(5000);
instead. That's a sort of "asynchronous wait". That way, the UI thread won't be blocked. The task returned by CountCharsAsync will complete about 5 seconds later, at which point the next part of button1_Click will execute.
Compare that with this code:
Task<int> tsk = new Task<int>(CountChars);
tsk.Start();
That will execute CountChars in the default task scheduler - on the thread pool. Blocking that thread doesn't affect the UI at all. (As noted in comments, that's not a good way of starting a task these days. Either call an async method, or use Task.Run.)
While Daisy's answer makes it not block UI, your CountCharsAsync method is "fake" async. If you have Resharper (not sure if this a feature of VS or R#) you will have a warning:
Async method lacks 'await' operators and will run synchronously
This is because async Task does not do all the magic - in your case it does absolutetly nothing. Nowhere you make it run on another thread.
Proper implementation would be:
private int CountChars()
{
int count = 50;
Thread.Sleep(5000);
return count;
}
private Task<int> CountCharsAsync() // notice no async!
{
return Task.Run(CountChars);
}
Daisy's implementation would still block if you replaced Thread.Sleep with for example a for loop to max integer.
My version in fact shifts execution to new thread.
I have an application which plays a recording stream, it has a COM Interface to provide functionality to start replay stream along with other control variables. I want to accomplish the following task (test case) using an button click event (Visual Studio Desktop Form Application):
Play recording from 0 second (0 min) for 10 seconds
Then play recording from 60 second (1 min) for 15 seconds
Finally play recording from 120 second (2 min) for 20 seconds. (stream length in approx 3 min)
I am creating thread for each of the above task from 1-3 and then I am using join method to wait for each task to be completed and then start the next thread.
My code:
private void btnReplayForward_Click(object sender, EventArgs e) {
Thread replayAtThread = new Thread(() => mpd.startReplayAt3(0, 10));
replayAtThread.Start();
replayAtThread.Join();
Thread replayAtThread1 = new Thread(() => mpd.startReplayAt3(60, 15));
replayAtThread1.Start();
replayAtThread1.Join();
Thread replayAtThread2 = new Thread(() => mpd.startReplayAt3(120, 20));
replayAtThread2.Start();
replayAtThread2.Join();
replayAtThread.Abort();
replayAtThread1.Abort();
replayAtThread2.Abort();
}
mpd is just an instance of an class that uses COM Interface, in a nutshell this is what startReplayAt3 method looks like
public bool startReplayAt3(double start, double duration)
{
//Set start and duration
//Start replay at start and duration values
bool isReplay = //get replay value, true if replay running, false if stopped
while (isReplay)
isReplay = //get replay value, true if replay running, false if stopped
return isReplay;
}
However, on the actual interface I am not seeing the desired results, it performs task 1, then does something with task 2 but skip the replay part entirely, then performs task 3. Next time when I click the button, it skips task 1, goes straight to task 2 and ends without performing task 3. So as you can see it is very unpredictable and strange behavior.
Why could be the cause, I am making sure that my thread are in sync but it doesn't seem to reflect in the UI of the application I am running.
I'm not entirely sure about the issue you're seeing with the threads :\. The implementation seems a little off, the .Abort() calls seem redundant since the thread will be completed by the time you're calling the .Abort().
Why not use asynchronous functionality?
await Task.Run(() => mpd.startReplayAt3(0, 10));
await Task.Run(() => mpd.startReplayAt3(60, 15));
await Task.Run(() => mpd.startReplayAt3(120, 20));
or:
var replayTasks = new List<Task>();
replayTasks.Add(Task.Run(() => mpd.startReplayAt3(0, 10)));
replayTasks.Add(Task.Run(() => mpd.startReplayAt3(60, 15)));
replayTasks.Add(Task.Run(() => mpd.startReplayAt3(120, 20)));
Task.WaitAll(replayTasks.ToArray());
or:
var replayTasks = new Task[] {
Task.Run(() => mpd.startReplayAt3(0, 10)),
Task.Run(() => mpd.startReplayAt3(60, 15)),
Task.Run(() => mpd.startReplayAt3(120, 20))
};
Task.WaitAll(replayTasks);
Like yourself I used to create many threads for executing tasks simultaneously, but I have fallen in love with async/await.
Make sure to change your _Click method to an asynchronous method using the async keyword.
From your description of the program's behavior, it seems to me that startReplayAt3 in fact only starts the replay.
What you want to do is start the replay, then wait until it finishes, and then start the next replay.
If the COM object gives you an event that is raised when the replay completes, then you're good; you should wrap that event into a task, and use await to consume it, something like this:
public static Task ReplayAsync(this MPD mpd, int start, int duration)
{
var tcs = new TaskCompletionSource();
ReplayFinishedHandler handler = null;
handler = (s, e) => { tcs.TrySetCompleted(); mpd.ReplayFinished -= handler; };
mpd.ReplayFinished += handler;
mpd.startReplayAt3(start, duration);
return tcs.Task;
}
used as such:
private async void btnReplayForward_Click(object sender, EventArgs e)
{
await mpd.ReplayAsync(0, 10);
await mpd.ReplayAsync(60, 15);
await mpd.ReplayAsync(120, 20);
}
But some COM objects don't let you know when they're done (notably, a lot of media players are really bad at this). In that case, you'll either have to poll some kind of IsPlaying flag on the COM object, or just use a timeout like this:
public static Task ReplayAsync(this MPD mpd, int start, int duration)
{
mpd.startReplayAt3(start, duration);
return Task.Delay(TimeSpan.FromSeconds(duration));
}
I'm making a simple application, and I need to do some stuff, and update a progress bar. I do some stuff, wait for 1 second, and if the execution did OK, I increase a progress bar, do some other stuff, wait another second, and if OK, increase the progress bar, and so on, 7 times. By stuff, it means I'm connection to an electronic board via RS232, send some commands, it executes, and after 1 second I check if everyting did fine on the board. I need to wait 1 second for some analogic stuff on the board.
The problem is about waiting that one second. If I use Thread.Sleep(1000), the entire UI freezes (as expected) and the progress bar works in a "not synchronized" wait for the same reason.
My code is like:
progressBar1.Value = 0;
/* Do some stuff */
Thread.Sleep(1000);
/* Check the stuff */
progressBar1.Value = 1;
/* Do some stuff */
Thread.Sleep(1000);
/* Check the stuff */
progressBar1.Value = 2;
/* Do some stuff */
Thread.Sleep(1000);
/* Check the stuff */
and so on... 7 times.
The "stuff" are all different for every step.
Which is the best way to make my code to wait for 1 second?
Thanx for any help!!!
You should use the Task Parallel Library (TPL) if your version of .NET Framework supports it. This is exactly the kind of problem the TPL was designed to solve. To do that, you would start an asynchronous Task, which is an encapsulation on top of the Thread class.
Conceptually, you should be creating a new thread for the connection to the RS232 board. Your main thread (UI thread) keeps executing and does not freeze the UI. If this is a Windows application, you should read more about multithreaded programming because using a single thread in a Windows application that needs to do many things "at once" will always cause blocking and freezing issues.
If your .NET Framework version does NOT support TPL, then you should use a class called BackgroundWorker. Here's a small example to get you started: http://msdn.microsoft.com/en-us/library/ywkkz4s1.aspx
PS: My answer is based on the assumption that you are programming a Windows Forms application.
Here is a very simple, contrived WinForms example:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;
namespace ProgressBar
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnDoWork_Click(object sender, EventArgs e)
{
Task task1 = new Task(() => { System.Threading.Thread.Sleep(5000); });
Task task2 = new Task(() => { System.Threading.Thread.Sleep(5000); });
Task task3 = new Task(() => { System.Threading.Thread.Sleep(5000); });
Task task4 = new Task(() => { System.Threading.Thread.Sleep(5000); });
task1.ContinueWith((t) =>
{
if (t.Exception != null)
t.Exception.Handle(ex =>
{
//do something
return true;
});
progressBar.Value = 25;
}, TaskScheduler.FromCurrentSynchronizationContext()).ContinueWith((t) => task2.Start());
task2.ContinueWith((t) =>
{
if (t.Exception != null)
t.Exception.Handle(ex =>
{
//do something
return true;
});
progressBar.Value = 50;
}, TaskScheduler.FromCurrentSynchronizationContext()).ContinueWith((t) => task3.Start());
task3.ContinueWith((t) =>
{
if (t.Exception != null)
t.Exception.Handle(ex =>
{
//do something
return true;
});
progressBar.Value = 75;
}, TaskScheduler.FromCurrentSynchronizationContext()).ContinueWith((t) => task4.Start());
task4.ContinueWith((t) =>
{
if (t.Exception != null)
t.Exception.Handle(ex =>
{
//do something
return true;
});
progressBar.Value = 100;
}, TaskScheduler.FromCurrentSynchronizationContext());
task1.Start();
}
}
}
Basically, just create a task for each operation; then on the continuation of that task, check the AggregateException (this is very important, as if you don't check it and there is an exception, your program will crash when the task is garbage collected). On the completion of that continuation, just fire the next task. If you need to do UI access from one of the tasks, make sure that you invoke that task from the CurrentSynchronizationContext.
The code below is a simplified example of a problem I am having. What happens upon the form loading - the For Loop will create a new task per iteration, then go as far as entering the 'if (pic.InvokeRequired)' section, but will return back to the For Loop and continue to iterate BEFORE any of the Tasks go through their respective invocations of method() after pic.BeginInvoke() is called.
What I am trying to achieve is for the invoking to complete it's second pass through method() and eventually changing the pic.BackColor to Color.Blue. I imagine this is possible, no? I've spent a couple hours searching around and could not find a satisfactory answer to this problem..
To run this code yourself, make a new WinForms Application Project (I'm using Visual Studio 2012) and add a PictureBox called 'pic'. Insert the code below.
Thank you for any and all help!
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 5; i++)
{
Task task = Task.Factory.StartNew(() => method());
task.Wait(); //Waits for task to complete before proceeding
}
}
public delegate void delegate_method();
private void method()
{
if (pic.InvokeRequired)
{
delegate_method dm = new delegate_method(() => method());
pic.BeginInvoke(dm); //If ran once (without the loop in Form1_Load) it would call 'method()' immediately from here.
}
else
{
pic.BackColor = Color.Blue;
}
}
I can appreciate the question because in some situations blocking may be preferable to full-on async (although it's more of a last resort measure).
The answer here depends on whether your async call (the actual meat of the work which happens in the background before you get to invoke an action on the UI thread - the part of the code which I'm assuming you chose to omit for the sake of simplicity) does any UI-bound work. If it does, you're out of luck and using Application.DoEvents() is your best bet.
If, however, it does not, and you have enough control over the async code, what you can do is instead of trying to invoke the UI from within your task, pass the Action describing the work back to your UI thread (as your Task's Result) and then handle its invocation there.
Note that I've simplified the implementation of Method() as it no longer gets called from non-UI threads.
WARNING: SIMPLIFIED CODE, NOT SUITABLE FOR PRODUCTION.
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PicInvoke
{
public partial class Form1 : Form
{
public Form1()
{
this.InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Stopwatch sw;
// Sequential processing.
sw = Stopwatch.StartNew();
this.DoWorkAndBlockSequential();
sw.Stop();
MessageBox.Show(string.Format("Sequential work complete. Time taken: {0:0.000}s.", (double)sw.ElapsedMilliseconds / 1000.0));
// Parallel processing.
sw = Stopwatch.StartNew();
this.DoWorkAndBlockParallel();
sw.Stop();
MessageBox.Show(string.Format("Parallel work complete. Time taken: {0:0.000}s.", (double)sw.ElapsedMilliseconds / 1000.0));
}
private void DoWorkAndBlockSequential()
{
for (int i = 0; i < 5; i++)
{
var task = this.DoWorkAsync();
// Block the UI thread until the task has completed.
var action = task.Result;
// Invoke the delegate.
action();
}
}
private void DoWorkAndBlockParallel()
{
var tasks = Enumerable
.Range(0, 5)
.Select(_ => this.DoWorkAsync())
.ToArray();
// Block UI thread until all tasks complete.
Task.WaitAll(tasks);
foreach (var task in tasks)
{
var action = task.Result;
// Invoke the delegate.
action();
}
}
private Task<Action> DoWorkAsync()
{
// Note: this CANNOT synchronously post messages
// to the UI thread as that will cause a deadlock.
return Task
// Simulate async work.
.Delay(TimeSpan.FromSeconds(1))
// Tell the UI thread what needs to be done via Task.Result.
// We are not performing the work here - merely telling the
// caller what needs to be done.
.ContinueWith(
_ => new Action(this.Method),
TaskContinuationOptions.ExecuteSynchronously);
}
private void Method()
{
pic.BackColor = Color.Blue;
}
}
}
I'm trying to figure out how to work with the Task class. In the past I have always used the regular Thread class, but I'm trying to grasp all of the asynchronous programming...
As an example, I created a main Winforms application that has all the code.
The relevant code for my problem is:
//Relevant delegates
public delegate void MethodAction(int num);
public delegate void MethodConversion();
public delegate void OnCompletionAction(string completiontext);
//Button user presses
private void button4_Click(object sender, EventArgs e)
{
richTextBox1.Clear();
sw.Reset();
sw.Start();
Sync.RunAsync3(calcSim);
}
//The method that simulates a calculation by adding a sleep
//the input param threadlength is just to allow threads to take longer than others
//since I'm multithreading, I have to invoke the writing code on the windows RichTextbox control
private void calcSim(int threadlength)
{
string threadname = Thread.CurrentThread.Name;
for (int i = 0; i < 10; i++) //Thread calc should take 3s
{
Thread.Sleep(300 + threadlength);
richTextBox1.Invoke((MethodConversion)(() =>
{
richTextBox1.AppendText(string.Format("Thread: {0}\tVersion: {1}\n", threadname, (i + 1).ToString()));
}));
}
}
//Class that contains the different processing methods
public static class Sync
{
public static event OnCompletionAction OnProcCompletion;
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
Task.WaitAll(t);
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
}
The problem lies within Task.WaitAll(t)... For some reason, which I can't figure out, it completely blocks on that line and doesn't respond anymore. If I omit that line, the form gets updated in realtime and the execution take about 3 seconds.
My question is: why isn't Task.WaitAll() blocking the UI thread for 3 seconds before releasing it and allowing the rest of the code to execute?
I know it should be blocking the UI for some time (until all threads are calculated), but it blocks the complete app endlessly. It seems to be waiting forever?
EDIT
I've been suggested to use WhenAll instead of WaitAll. I have rewritten RunAsync3 as follows:
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
//Task.WaitAll(t); -> deadlock
Task.WaitAll(new Task [] { Task.WhenAll(t) });
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
But this is still getting deadlocked...? I might be using the WhenAll incorrectly?
EDIT 2
Because everybody claiming that I was blocking the UI thread were right, I decided to try this another way: by running a new thread as my calling thread inside the UI thread (so that blocking now would occur on my thread instead of UI thread). This works, but is obviously not the best way to do this!
private void button4_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(() =>
{
richTextBox1.Invoke((MethodConversion)(() => richTextBox1.Clear()));
sw.Reset();
sw.Start();
Sync.RunAsync3(calcSim);
}));
t.Start();
}
public static void RunAsync3(MethodAction doM)
{
Task[] t = new Task[4];
for(int i = 0; i < 4; i++)
{
t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
}
Task.WaitAll(t);
//Task.WaitAll(new Task [] { Task.WhenAll(t) });
if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}
You're causing a deadlock.
The UI thread is waiting for 4 tasks to be completed.
On the other hand, those 4 tasks, running calcSim are trying to invoke code on the UI thread -> Deadlock.
You should be using Task.WhenAll() instead. That method will return a new task that will be marked as completed when all your for tasks have completed. If you await that task, your UI thread will be freed, and so calcSim will be able to invoke code on the UI thread, avoiding a deadlock.
Update
You're using it wrong. You're still using WaitAll, which is a blocking call. You should replace it with WhenAll.
await Task.WhenAll(t);
From the documentation:
Creates a task that will complete when all of the supplied tasks have
completed.
By calling await on the result, your UI thread will be free - until all 4 tasks complete. When that happens, your RunAsync3 method will resume.
Task.WaitAll blocks and waits for all task to complete and you are calling it on the UI thread.
All your task are trying to call richTextBox1.Invoke (in the UI thread) but your UI thread is blocked in Task.WaitAll. Deadlock.
Because it waits as your threads finish. They run exactly 3 seconds 300X10