I`m new to TPL and need some help in understanding .continueWith. Can you pls tell me what is wrong in first task-continuation and how is second one correct?
List<int> input = new List<int> { 1, 2, 3, 4, 5 };
//Gives cast error at the second continuation: cannot implicitly convert
//Task to Task<List<int>>
Task<List<int>> task = Task.Factory.StartNew<List<int>>(
(state) => { return (List<int>)state; }, input)
.ContinueWith<List<int>>(
(prevTask => { return (List<int>)prevTask.Result; }))
.ContinueWith(
(prevTask => { Console.WriteLine("All completed"); }));
//Works fine
Task<List<int>> task1 = Task.Factory.StartNew<List<int>>(
(state) => { return (List<int>)state; }, input);
task1.ContinueWith<List<int>>(
(prevTask => { return (List<int>)prevTask.Result; }))
.ContinueWith(
(prevTask => { Console.WriteLine("All completed"); }));
The first chain of method calls you made ends with ContinueWith() which returns a Task object which can't be assigned to a Task<List<int>>:
Task.Factory.StartNew<List<int>>(...) // returns Task<List<int>>
.ContinueWith<List<int>>(...) // returns Task<List<int>>
.ContinueWith(...); // returns Task
But in the second one, the result of the last ContinueWith is not assigned to anything, so works fine.
For the first one to work, either define task as Task:
Task task = Task.Factory.StartNew<List<int>>(
(state) => { return (List<int>)state; }, input)
.ContinueWith<List<int>>(
(prevTask => { return (List<int>)prevTask.Result; }))
.ContinueWith(
(prevTask => { Console.WriteLine("All completed"); }));
Or make the last call a generic one:
Task<List<int>> task = Task.Factory.StartNew<List<int>>(
(state) => { return (List<int>)state; }, input)
.ContinueWith<List<int>>(
(prevTask => { return (List<int>)prevTask.Result; }))
.ContinueWith<List<int>>(
(prevTask => { Console.WriteLine("All completed"); }));
Related
I want to translate the following code into a reactive flow (using System.Reactive in C#).
Method1, Method2 and Method3 are long running tasks. The result of Method2 is necessary in order to call Method3, but Method1 and Method2 can run in parallel. If result1 == null the whole operation can be terminated early with null.
Usually, Method2 returns faster than Method1, so Method3 could be started before Method1 finishes.
var result1 = Method1();
if (result1 == null) return null;
var result2 = Method2();
string result3 = null;
if (result2 != null)
{
result3 = Method3(result2);
}
var combinedResult = CreateResult(result1);
if (result2 != null)
{
combinedResult.Attr2 = result2;
}
if (result3 != null)
{
combinedResult.Attr3 = result3;
}
I am lost between nested functions and generics. The following code does not compile, because it has issues with generics and return types (especially the nested Select does not return a value but an Observable).
var observable1 = Observable.Start(() => Method1());
var observable2 = Observable.Start(() => Method2());
Observable.Zip(observable1, observable2, (result1, result2) =>
{
if (result2 != null)
{
var observable3 = Observable.Start(() => Method3(result2));
return observable3.Select(result3 =>
{
return SuperCombiner(result1, result2, result3);
};
}
return SuperCombiner(result1, null, null);
};
Here's what you need to get this to work:
var inner =
from m2 in Observable.Start(() => Method2())
from m3 in Observable.Start(() => Method3(m2))
select new { m2, m3 };
var query =
Observable
.Start(() => Method1())
.Publish(m1s =>
m1s
.Zip(
inner.TakeUntil(m1s.Where(m1 => m1 == null)),
(m1, m23) => new { m1, m23.m2, m23.m3 }))
.Where(x => x.m1 != null);
I have tested this using the following code:
public string Method1()
{
Console.WriteLine("Method1 Start");
Thread.Sleep(TimeSpan.FromSeconds(2.0));
Console.WriteLine("Method1 End");
return null; //"1";
}
public string Method2()
{
Console.WriteLine("Method2 Start");
Thread.Sleep(TimeSpan.FromSeconds(3.0));
Console.WriteLine("Method2 End");
return "2";
}
public string Method3(string x)
{
Console.WriteLine("Method3 Start");
Thread.Sleep(TimeSpan.FromSeconds(2.0));
Console.WriteLine("Method3 End");
return $"3-{x}";
}
The query only produces a value when Method1 returns a non-null value - otherwise it completes without producing a value.
Method3 is executed immediately after Method2 is complete unless Method1 has already returned null in which case Method3 is not executed.
This is computationally the most efficient implementation of what you asked for.
I've added some improvements to your draft and now it works as you described:
var stream1 = Observable.Start(Func1);
var stream2 = Observable.Start(Func2);
Observable.Zip(stream1, stream2, (res1, res2) =>
{
if (res1 == null)
return Observable.Start(() => new string[] { null });
if (res2 == null)
return Observable.Start(() => new string[] { res1, null });
return Observable.Start(() => Func3(res2)).Select(res3 => new[] { res1, res2, res3 });
})
.Merge()
.Subscribe(result =>
{
// 'result' is an array
// result[0] - result of Func1
// result[1] - result of Func2
// result[2] - result of Func3
// result.Length == 1 - means that Func1 returned 'null'
// result.Length == 2 - means that Func2 returned 'null'
});
But it's not a real 'Reactive' way because it contains imperative statements (like if operators for example).
I am writing some complex tasks and I can't do success to solve the problem.
I open some tasks for searching some data asynchronously.
At the end I wait for all tasks.
I want to run on all the data and does not stop the tasks until they all finish.
But, when one of the tasks finds some relevant data, I want to continue with the code that is after the wait all tasks, but at the same time, I want to continue searching with my tasks (until all the data will be read).
Here I found a way how to continue the code after the wait all if one of the tasks finds the data, the problem is that it also stops all tasks from running.
Here is my code (this is just code for demonstration of the problem).
private static void RunTasks()
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Task<bool> t0 = Task.Factory.StartNew<bool>(() => Find(1, 2));
Task<bool> t1 = Task.Factory.StartNew<bool>(() => Find(4, 7));
Task<bool> t2 = Task.Factory.StartNew<bool>(() => Find(13, 14));
t0.ContinueWith(_ =>
{
if (t0.Result)
tcs.TrySetResult(t0.Result);
});
t1.ContinueWith(_ =>
{
if (t1.Result)
tcs.TrySetResult(t1.Result);
});
t2.ContinueWith(_ =>
{
if (t2.Result)
tcs.TrySetResult(t2.Result);
});
tcs.Task.Wait();
Console.WriteLine("Found");
ContinueWork(); //Runs after at least one data found or when all tasks finish.
}
//Just for demonstration...
private static bool Find(int a, int b)
{
Console.WriteLine("a: " + a + " b: " + b);
return a == 4 && b == 7 ? true : false;
}
How can I write it so that when some data is found it will continue to ContinueWork method and also will continue with reading the data with the tasks?
Thanks.
This is not the cleanest way but it will serve your purposes:
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Task<bool>[] tasks = new Task<bool>[3];
tasks[0] = Task.Factory.StartNew<bool>(() => Find(1, 2));
tasks[1] = Task.Factory.StartNew<bool>(() => Find(4, 7));
tasks[2] = Task.Factory.StartNew<bool>(() => Find(13, 14));
tasks[0].ContinueWith(_ =>
{
if (tasks[0].Result)
tcs.TrySetResult(tasks[0].Result);
});
tasks[1].ContinueWith(_ =>
{
if (tasks[1].Result)
tcs.TrySetResult(tasks[1].Result);
});
tasks[2].ContinueWith(_ =>
{
if (tasks[2].Result)
tcs.TrySetResult(tasks[2].Result);
});
Task.WaitAny(tasks);
Console.WriteLine("Found");
ContinueWork();
I have a problem understanding how AttachedToParent parameter works.
Here is the sample code:
public static void Main(string[] args)
{
Task<int[]> parentTask = Task.Run(()=>
{
int[] results = new int[3];
Task t1 = new Task(() => { Thread.Sleep(3000); results[0] = 0; }, TaskCreationOptions.AttachedToParent);
Task t2 = new Task(() => { Thread.Sleep(3000); results[1] = 1; }, TaskCreationOptions.AttachedToParent);
Task t3 = new Task(() => { Thread.Sleep(3000); results[2] = 2; }, TaskCreationOptions.AttachedToParent);
t1.Start();
t2.Start();
t3.Start();
return results;
});
Task finalTask = parentTask.ContinueWith(parent =>
{
foreach (int result in parent.Result)
{
Console.WriteLine(result);
}
});
finalTask.Wait();
Console.ReadLine();
}
As I understand, when a Task has child Tasks, the parent Task finishes when all the child tasks are ready. The problem with this example is that the output looks like this:
0
0
0
This means that the parent Task was not waiting for its child tasks to finish. The only way to get a valid result 0 1 2 is to use Wait on all of the child Taks, by adding some piece of code like this before the return results; statement:
Task[] taskList = { t1, t2, t3 };
Task.WaitAll(taskList);
My question is this. Why do we use TaskCreationOptions.AttachedToParent when we also have to manually call Wait method for every child Task?
Edit:
While I was writing this question, I've changed code a little bit and now AttachedToParent works well. The only difference is that I've used parentTask.Start(); instead of the Task.Run();.
public static void Main(string[] args)
{
Task<int[]> parentTask = new Task<int[]>(()=>
{
int[] results = new int[3];
Task t1 = new Task(() => { Thread.Sleep(3000); results[0] = 0; }, TaskCreationOptions.AttachedToParent);
Task t2 = new Task(() => { Thread.Sleep(3000); results[1] = 1; }, TaskCreationOptions.AttachedToParent);
Task t3 = new Task(() => { Thread.Sleep(3000); results[2] = 2; }, TaskCreationOptions.AttachedToParent);
t1.Start();
t2.Start();
t3.Start();
//Task[] taskList = { t1, t2, t3 };
//Task.WaitAll(taskList);
return results;
});
parentTask.Start();
Task finalTask = parentTask.ContinueWith(parent =>
{
foreach (int result in parent.Result)
{
Console.WriteLine(result);
}
});
finalTask.Wait();
Console.ReadLine();
}
I still don't understand why there is a problem with the first example.
Look at this blog post: Task.Run vs Task.Factory.StartNew
The first example:
Task.Run(someAction);
is simplified equivalent of method:
Task.Factory.StartNew(someAction,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
I made little research, using reflector, here is a source of method Task.Run
public static Task Run(Func<Task> function, CancellationToken cancellationToken)
{
if (function == null)
throw new ArgumentNullException("function");
cancellationToken.ThrowIfSourceDisposed();
if (cancellationToken.IsCancellationRequested)
return Task.FromCancellation(cancellationToken);
else
return (Task) new UnwrapPromise<VoidTaskResult>(
(Task) Task<Task>.Factory.StartNew(function,
cancellationToken,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default),
true);
}
The important parameter of method Task.Factory.StartNew is TaskCreationOptions creationOptions. In method Task.Factory.StartNew that parameter equals TaskCreationOptions.DenyChildAttach. It mean that
an InvalidOperationException will be thrown if an attempt is made to
attach a child task to the created task
You need to change to TaskCreationOptions.None to achieve right behavior of code.
Method Task.Run does not provide ability to change TaskCreationOptions parameter.
I have the following code:
Task.Factory.ContinueWhenAll(items.Select(p =>
{
return CreateItem(p);
}).ToArray(), completedTasks => { Console.WriteLine("completed"); });
Is it possible to convert ContinueWhenAll to a synchronous method? I want to switch back between async and sync.
Edit: I should metnion that each of the "tasks" in the continuewhenall method should be executing synchronously.
If you want to leave your existing code intact and have a variable option of executing synchronously you should make these changes:
bool isAsync = false; // some flag to check for async operation
var batch = Task.Factory.ContinueWhenAll(items.Select(p =>
{
return CreateItem(p);
}).ToArray(), completedTasks => { Console.WriteLine("completed"); });
if (!isAsync)
batch.Wait();
This way you can toggle it programmatically instead of by editing your source code. And you can keep the continuation code the same for both methods.
Edit:
Here is a simple pattern for having the same method represented as a synchronous and async version:
public Item CreateItem(string name)
{
return new Item(name);
}
public Task<Item> CreateItemAsync(string name)
{
return Task.Factory.StartNew(() => CreateItem(name));
}
Unless am mistaken this is what you're looking for
Task.WaitAll(tasks);
//continuation code here
i think you can try this.
using TaskContinuationOptions for a simple scenario.
var taskFactory = new TaskFactory(TaskScheduler.Defau
var random = new Random();
var tasks = Enumerable.Range(1, 30).Select(p => {
return taskFactory.StartNew(() => {
var timeout = random.Next(5, p * 50);
Thread.Sleep(timeout / 2);
Console.WriteLine(#" 1: ID = " + p);
return p;
}).ContinueWith(t => {
Console.WriteLine(#"* 2: ID = " + t.Result);
}, TaskContinuationOptions.ExecuteSynchronously);
}).ToArray();
Task.WaitAll(tasks);
or using TPL Dataflow for a complex scenario.
var step2 = new ActionBlock<int>(i => {
Thread.Sleep(i);
Console.WriteLine(#"* 2: ID = " + i);
}, new ExecutionDataflowBlockOptions {
MaxDegreeOfParallelism = 1,
//MaxMessagesPerTask = 1
});
var random = new Random();
var tasks = Enumerable.Range(1, 50).Select(p => {
return Task.Factory.StartNew(() => {
var timeout = random.Next(5, p * 50);
Thread.Sleep(timeout / 2);
Console.WriteLine(#" 1: ID = " + p);
return p;
}).ContinueWith(t => {
Thread.Sleep(t.Result);
step2.Post(t.Result);
});
}).ToArray();
await Task.WhenAll(tasks).ContinueWith(t => step2.Complete());
await step2.Completion;
I was looking for this and I couldn't figure how to do it.
I have a some threats (tasks) in an App.
foreach (string targetMachine in targetMachines)
{
Task<int> task = Task.Run(() => Magic(targetMachine));
}
I created a task for every object in an array.
The task returns a value.
I want to process the values and act based on them. As example, if task return 0 dont do anything, if returns 1 write a log, if returns 2 run a process.
How can I acoomplish this?
If I process the return values inside the foreach:
foreach (string targetMachine in targetMachines)
{
Task<int> task = Task.Run(() => Magic(targetMachine));
Task.Waitforexit()
if (task.result == 2)
{
do something
}
}
I think, task are not going to be useful and the programa will wait each task to be completed to continue.
It can be something like this:
foreach (string targetMachine in targetMachines)
{
Task.Run(() =>
{
var result = Magic(targetMachine);
if (result == 2)
{
DoSomething();
}
});
}
OR (using async/await)
foreach (string targetMachine in targetMachines)
{
var result = await Task.Run(() => Magic(targetMachine));
if (result == 2)
{
DoSomething();
}
}
OR (using ContinueWith)
foreach (string targetMachine in targetMachines)
{
Task<int>.Run(()=>Magic(targetMachine))
.ContinueWith(t =>
{
if (t.Result == 2)
{
DoSomething();
}
});
}
If you want to wait to finish all of your tasks
Parallel.ForEach(targetMachines, targetMachine =>
{
var result = Magic(targetMachine);
if (result == 2)
{
DoSomething();
}
});
Have a look at Task.ContinueWith()
http://msdn.microsoft.com/en-us/library/dd321405.aspx
When each task is complete it passes the result to the ContinueWith which can then either do nothing, log or call a method like you want.
Additionally you could run the foreach .AsParallel() and remove the tasks altogether.
http://msdn.microsoft.com/en-us/library/dd413602.aspx
I'll add a new variant in addition to the variants given in L.B.'s answer:
var tasks = targetMachines.Select(x => Magic(x));
Task.WaitAll(tasks); //fork-join
If you're using async, you can write:
var tasks = targetMachines.Select(x => Magic(x));
await Task.WhenAll(tasks); //fork-join
And instead of
var tasks = targetMachines.Select(x => Magic(x));
you can always write:
var tasks = targetMachines.Select(x =>
{
var result = Magic(x);
if (result == 2) DoSomething();
});
which liberates you from having to use ContinueWith.