EDIT SOLUTION: It appears the solution is to have code like below where I specify TaskContinuationOption.ExecuteSynchronously
public ActionBlock<DomainBaseFile[]> GetActionBlock()
{
var returnActionBlock = new ActionBlock<DomainBaseFile[]>(
n => Work(n)
);
returnActionBlock.Completion.ContinueWith((s, o) => FinalizeFiles(), new object(), TaskContinuationOptions.ExecuteSynchronously);
return returnActionBlock;
}
I have two tasks, FirstTask and SecondTask that are linked. Both tasks have things they have to do on completion i.e
firstTask.Complete.ContinueWith(t => ...
The problem I'm currently having is that the SecondTask Complete.ContinueWith seems to be running before the FirstTask.Complete.ContinueWith and the code is built assuming that First task is done.
I assume this is because the ContinueWith task runs whenever after the Completion signal is sent and isn't subject to ordering like the Complete propagation is.
Is there anyway for me to force SecondTask to not call it's Complete method till the FirstTask.Complete.ContinueWith is done?
Currently, I have
Task.WhenAll(firstBlock.Completion)
.ContinueWith(_ =>
secondBlock.Complete()
);
However, this Task.WhenAll is going to wait for the Completion and not the Completion.ContinueWith function to finish.
Any help is greatly appreciated.
Related
Thread ThreadWindow = new Thread(async () =>
{
WindowWPF windowWPF = new WindowWPF();
windowWPF.Show();
await Task.Run(() =>
{
while (true)
{
//code
}
});
//code works when it shouldn't be available
});
For some reason, the compiler suggests changing the last line to me: }); in }){}; what is this for?
The idea is to display the loading window and work with the data in parallel, after which the window should close.
It will not, as soon as await is hit, an incomplete Task will be returned and the job within await will be returned as a future callback if it's a bit long running job.
As you have made while(true) making the piece of code to execute infinitely, assuming that you are trying to do call and forget way, If so then don't use await. Also, Instead of you creating new Thread, try making use of Task as below
var task = new Task(() => MyLongRunningMethod(),
TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
task.Start();
I understand that the .Join() causes the threads to pause and wait till a thread finishes its work but how can I avoid the UI from getting frozen? This is what my codes look like"
Thread dataThread = new Thread(()=> data = getData(id));
dataThread.Start();
dataThread.Join();
Thread storingThread = new Thread(()=> storeData(data));
storingThread.Start();
I need to have the Join since the first thread returns an object containing data that needs to be stored through the second thread. But this causes a UI freeze. How can I implement these in maybe a Background thread? What do yall think I should change?
If you are using .Net framework >= 4.5 you can use Tasks
await Task.Run(() => data = getData(id));
await Task.Run(() => storeData(data));
Or in one command
await Task.Run(() => storeData(getData(id)));
If you don't have to wait till it's finished you can also do:
Task.Run(() => storeData(getData(id)));
It seems you don't need two threads:
Thread dataThread = new Thread(() => storeData(getData(id)));
dataThread.Start();
Note, that Task is preferable to Thread. Also, you probably should make use of await.
The answer has already been given. Just as an extra, I give mine.
You can also use ContinueWith like this:
Task<string>.Factory.StartNew(() => "Hey!").ContinueWith(t => Console.WriteLine(t.Result));
Put the whole work into one thread so the UI doesn't stop:
ThreadPool.QueueUserWorkItem( () => storeData(getData(id)));
Or for .Net 4
Task.Factory.StartNew(() => storeData(getData(id)));
Use the async / await keywords. Small example code:
private async void Method()
{
var result = await ExecuteAsync();
// result == true
}
private async Task<bool> ExecuteAsync()
{
//run long running action
return true;
}
In .net 4.0 you need to install Microsoft.Bcl.Async to use this feature.
A good introduction in this feature can be read on http://blog.stephencleary.com/2012/02/async-and-await.html
I'm hoping there is a simple answer here, and this is probably due to my misunderstanding of asynchronous operations...
I have a method that can be started manually or can autostart when the program loads. The async method works perfectly when invoked manually (on button press). However, when autoloaded the method just seems to skip the main "await" part of the method without performing any work, and skips straight to the end.
The whole process starts in this method:
private void StartBatch()
{
var batchSize = (int)BatchSizeSlider.Value;
if (_config.AutoStart)
{
ExecutionLogAddItem(string.Format("Auto batch processing started (batch size: {0})", batchSize.ToString()));
Task.Factory.StartNew(async () =>
{
await BatchTransfer(batchSize);
CompleteBatch();
});
}
else
{
var start = ConfirmStartBatch();
var doBatch = start.ContinueWith(async (continuation) =>
{
//start task
if (start.Result == true)
{
ExecutionLogAddItem("Batch processing started.");
ExecutionLogAddItem(string.Format("Batch size set at {0}", batchSize.ToString()));
await BatchTransfer(batchSize).ContinueWith((x) => CompleteBatch());
}
else
{
ExecutionLogAddItem("Batch processing aborted.");
}
});
}
}
If _config.AutoStart is true, the BatchTransfer method doesn't seem to do anything, instead the program skips straight to the CompleteBatch() method. If invoked manually everything works as expected.
The strange thing is, if I set a breakpoint on await BatchTransfer(batchSize) in the autostarted method, I can step through the code and the batch transfers take place. So when debugging it works, when not debugging it doesn't. Please help!
It is because -
Task.Factory.StartNew(async () =>
{
await BatchTransfer(batchSize);
CompleteBatch();
});
You are waiting for the inner task to complete with await but Task.Factory.StartNew(async () => itself is an asynchronous task and is not awaited. You should also wait for Task.Factory.StartNew(async () => like this -
await Task.Factory.StartNew(async () =>
When you are debugging, the separate thread that is calling inner task is held and you can see the execution but when running normally the background is still working, but you cannot see it since you didn't wait for the Task.Factory.StartNew(async () =>.
If you check the thread pool and thread id, I am sure you will see that they are different when debugging.
This blog might help you understand the situation - http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx
In order to use await you have to make your method async and call it without Task.Factory.StartNew. One more thing, instead of void make return type as Task of your method because void async are fire and forget. You will not able to track them.
private async Task StartBatch()
{
await BatchTransfer(batchSize);
CompleteBatch();
}
Check this link. It have very basic demonstration of async and it is very helpful in understanding how asynchrony works. Six Essential Tips For Async - Introduction. It includes six tips which are very essential. I recommend you go through all of them but to understand current question situation you can go through Tip 1 whose title is Async void is for top-level event-handlers only.
I have an external dll with some methods I need to call. Also, I want to be able to configure a timeout for executing these methods, in order to abort them if execution time > config timeout.
I call these methods on different tasks, like this:
Parallel.ForEach(....
{
Func<object> asyncFucntion = () => DynamicCall(method, paramList);
IAsyncResult ar = asyncFucntion.BeginInvoke(null, null);
if (ar.AsyncWaitHandle.WaitOne(timeout, true))
{
return asyncFucntion.EndInvoke(ar);
}
else
{
//HERE I NEED to stop DynamicCall. Timeout was EXCEEDED
}
});
Now, I have the possibility to get the DynamicCall Thread id and abort it. Is there any other way around? A more light way? I can't use the Cancellation Tokes, since i can't modify the external Dll
Thanks,
Alex
Aborting a thread (especially a pool thread) is a really horrible thing to do. You may consider just letting each asyncFunction call come to an end naturally, without observing its result in case of time-out. See "How do I cancel non-cancelable async operations?"
On a side note, you're using Parallel.ForEach quite inefficiently here, the operation is taking roughly two times more threads than really needed. Without Parallel.ForEach, it might look like below, which is a better version, IMO:
var tasks = methods.Select(method =>
{
Func<object> asyncFunction = () => DynamicCall(method, paramList);
var task = Task.Factory.FromAsync(
(asyncCallback, state) => asyncFunction.BeginInvoke(asyncCallback, state),
(asyncResult) => asyncFunction.EndInvoke(asyncResult),
null);
return Task.WhenAny(task, Task.Delay(timeout)).Unwrap();
});
Task.WhenAll(tasks).Wait(); // or Task.WaitAll();
With the code below, the final UI updates made in the final ContinueWith never take place. I think it is because of the Wait() I have at the end.
The reason I am doing that is because without the Wait, the method will return the IDataProvider before its finished being constructed in the background.
Can someone help me get this right?
Cheers,
Berryl
private IDataProvider _buildSQLiteProvider()
{
IDataProvider resultingDataProvider = null;
ISession session = null;
var watch = Stopwatch.StartNew();
var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
// get the data
var buildProvider = Task.Factory
.StartNew(
() =>
{
// code to build it
});
// show some progress if we haven't finished
buildProvider.ContinueWith(
taskResult =>
{
// show we are making progress;
},
CancellationToken.None, TaskContinuationOptions.None, uiContext);
// we have data: reflect completed status in ui
buildProvider.ContinueWith(
dataProvider =>
{
// show we are finished;
},
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, uiContext);
try {
buildProvider.Wait();
}
catch (AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
Console.WriteLine(e.Message);
}
Console.WriteLine("Exception handled. Let's move on.");
CurrentSessionContext.Bind(session);
return resultingDataProvider;
}
====
just to be clear
I am not having trouble talking to the ui thread. The first continue with updates the ui just fine. The trouble I am having is the timing of the last ui update and the return of the data provider.
I commented out some of the code to reduce the noise level in tis post and focus on the task sequencing.
====
ok, working code
private void _showSQLiteProjecPicker()
{
var watch = Stopwatch.StartNew();
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
ISession session = null;
// get the data
var buildProvider = Task.Factory.StartNew(
() =>
{
var setProgress = Task.Factory.StartNew(
() =>
{
IsBusy = true;
Status = string.Format("Fetching data...");
},
CancellationToken.None, TaskCreationOptions.None, uiScheduler);
var provider = new SQLiteDataProvider();
session = SQLiteDataProvider.Session;
return provider;
});
buildProvider.ContinueWith(
buildTask =>
{
if(buildTask.Exception != null) {
Console.WriteLine(buildTask.Exception);
}
else {
Check.RequireNotNull(buildTask.Result);
Check.RequireNotNull(session);
_updateUiTaskIsComplete(watch);
CurrentSessionContext.Bind(session);
var provider = buildTask.Result;
var dao = provider.GetActivitySubjectDao();
var vm = new ProjectPickerViewModel(dao);
_showPicker(vm);
}
},
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, uiScheduler);
}
UPDATE BELOW
This code doesn't look like it warrants TPL to me. Looks like maybe a good use for a BackgroundWorker instead!
Either way, the updates are probably not taking place because you can't update the UI from a separate thread -- you need to run the update on the UI thread. You should use the Dispatcher for this (http://stackoverflow.com/questions/303116/system-windows-threading-dispatcher-and-winforms contains info for both WPF and WinForms)
Update:
So I obviously missed some of the code so here's a revised answer. First of all, Nicholas is correct -- .ContinueWith returns a new task (http://msdn.microsoft.com/en-us/library/dd270696.aspx). So instead of
var result = Task.Factory.StartNew(...);
result.ContinueWith(...);
you probably want to create a new task and then make all the ContinueWith() calls and assign to the task and then call .Start() on the task. Something like:
var task = new Task(...).ContinueWith(...);
task.Start();
However, there is a flaw in the design to begin with (as I see it)! You're trying to run this code async, wihch is why you're using threads and TPL. However, you're calling buildProvider.Wait(); on the UI thread which blocks the UI thread until this task completes! Aside from the issue of repainting the UI in the ContinueWith() while the UI thread is blocked, there's no benefit to multithreading here since you're blocking the UI thread (a major no-no). What you probably want to do is stick the Bind()-ing inside a ContinueWith or something so that you don't have to call Wait() and block the UI thread.
My $0.02 is that if you expect the query to take a long time what you really want is 2 threads (or tasks in TPL)-- one to perform the query and one to update the UI at intervals with status. If you don't expect it to take so long I think you just want a single thread (Task) to query and then update the UI when it's done. I would probably do this via BackgroundWorker. TPL was built for managing lots of tasks and continuations and such but seems overkill for this kind of thing -- I think you could do it using a BackgroundWorker in a lot less code. But you mention you want to use TPL which is fine, but you're going to have to rework this a bit so that it actually runs in the background!
PS - you probably meant to put the Console.WriteLine("Exception handled. Let's move on."); inside the catch
I'm a little hazy, but last time I used the TPL I found it confusing. ContinueWith() returns a new Task instance. So you need to assign the second ContinueWith() result to a new variable, say var continuedTask = builderProvider.ContinueWith(...), and then change the last one to reference continuedTask.ContinueWith() instead of buildProvider.ContinueWith(). Then Wait() on the last Task.
Hope that helps!