Async call for delegate in cycle - c#

I need to call asynchronously number of delegates for the same function.
The question is how i should treat the call back function ?
we have couple of delegates running so CallbackMethod doesn't mean that that all async delegates finished.
AsyncMethodCaller c = new AsyncMethodCaller(instance.dummyMethod);
for (int i = 0; i < 100; i++)
{
IAsyncResult res = c.BeginInvoke(5000,
out dummy,
new AsyncCallback(CallbackMethod),
"executed on thread {0}, with result value \"{1}\".");
}

I would consider looking at using Tasks provided with TPL.
var task1 = Task.Run(() => instance.dummyMethod)
.ContinueWith((completedTask) => Console.WriteLine("Each callback here. Result: " + completedTask.Result));
// Blocks calling thread until all tasks are done.
Task.WaitAll(new [] { task1, task2 });
The WaitAll all ensures that all Tasks are done before continuing on the main thread. The above allows you to implement individual callbacks.
Alternatively use a single callback when All the async methods are complete:
Task.Factory.ContinueWhenAll(new [] { task1, task2 },
(allTasks) => Console.WriteLine("Callback when all are done."));

I would be inclined to use Microsoft's Reactive Framework (NuGet "Rx-Main") for this as it would be so much simpler.
Here's the code:
var query =
from n in Observable.Range(0, 100)
from dummy in Observable.Start(() => instance.dummyMethod())
select dummy;
query
.Subscribe(
dummy =>
{
Console.WriteLine(dummy.ToString());
},
() =>
{
Console.WriteLine("Done.");
});
The .Subscribe method has a callback for each dummy value produced as well as a "done" callback when all the values have been returned.
The query runs on multiple threads automatically for you.

Related

Stuck at Task.WaitAll(tasks.ToArray()) while using Task.Start to trigger the tasks

We had something like below
List<string> uncheckItems = new List<string>();
for (int i = 0; i < 100; i++)
{
uncheckItems.Add($"item {i + 1}");
}
var tasks = uncheckItems.Select(item =>
new Task(async () => await ProcessItem(item))
);
// Do some preparations
foreach (var task in tasks)
{
task.Start();
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("=====================================================All finished");
It seems to make sense but the program never able to reach the all finished line.
And if I adjust the workflow to run tasks immediately like remove the task.Start() loop and change to
var tasks = uncheckItems.Select(async item =>
await ProcessItem(item)
);
Then it works.
However, I wonder
Why it stucks?
Is there any way we can keep the workflow(create tasks without trigger them directly and start them later on) and still able to utilize WaitAll()?
The reason is the lazy enumeration evaluation, you are starting different tasks than waiting with Task.WaitAll. This can be fixed for example with next:
var tasks = uncheckItems.Select(item =>
new Task(async () => await ProcessItem(item))
)
.ToArray();
Though it will not achieve your goal (as I understand) of waiting all ProcessItem to finish. You can do something like new Task(() => ProcessItem(item).GetAwaiter().GetResult()) but I think it would be better to change your approach, for example make ProcessItem return a "cold" task or using your second snippet and moving tasks creation to the point where they needed to be started.
You should be next to the world expert in Task to be using the constructor. The documentation warns against that:
This constructor should only be used in advanced scenarios where it is required that the creation and starting of the task is separated.
Rather than calling this constructor, the most common way to instantiate a Task object and launch a task is by calling the static Task.Run(Action) or TaskFactory.StartNew(Action) method.
If a task with no action is needed just for the consumer of an API to have something to await, a TaskCompletionSource should be used.
The Task constructor produces a non-started Task that will only start when Task.Start() is invoked, as you discovered.
The Task constructor also receives an Action (or Action<T>), so the return value is ignored. That means that, after started, the task will end as soon as async () => await ProcessItem(item) yields.
What you need is:
await Task.WhenAll(Enumerable.Range(0, 100).Select(i => ProcessItem($"item {i + 1}"));
Or, if you really have to block:
Task
.WhenAll(Enumerable.Range(0, 100).Select(i => ProcessItem($"item {i + 1}"))
.GetAwaiter().GetResult();
Get the select out of there.
List<string> uncheckItems = new List<string>();
for (int i = 0; i < 100; i++)
{
uncheckItems.Add($"item {i + 1}");
}
var tasks = new List<Task>();
foreach(var item in uncheckedItems) {
tasks.Add(Task.Run(() => ProcessItem(item)));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("========All finished");
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.waitall?view=net-6.0

Is there a proper pattern for multiple ContinueWith methods

In the docs for TPL I found this line:
Invoke multiple continuations from the same antecedent
But this isn't explained any further. I naively assumed you could chain ContinueWiths in a pattern matching like manner until you hit the right TaskContinuationOptions.
TaskThatReturnsString()
.ContinueWith((s) => Console.Out.WriteLine(s.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith((f) => Console.Out.WriteLine(f.Exception.Message), TaskContinuationOptions.OnlyOnFaulted)
.ContinueWith((f) => Console.Out.WriteLine("Cancelled"), TaskContinuationOptions.OnlyOnCanceled)
.Wait();
But this doesn't work like I hoped for at least two reasons.
The continuations are properly chained so the 2nd ContinueWith gets the result form the 1st, that is implemented as new Task, basically the ContinueWith task itself. I realize that the String could be returned onwards, but won't that be a new task with other info lost?
Since the first option is not met, the Task is just cancelled. Meaning that the second set will never be met and the exceptions are lost.
So what do they mean in the docs when they say multiple continuations from the same antecedent?
Is there a proper patter for this or do we just have to wrap the calls in try catch blocks?
EDIT
So I guess this was what I was hoping I could do, note this is a simplified example.
public void ProccessAllTheThings()
{
var theThings = util.GetAllTheThings();
var tasks = new List<Task>();
foreach (var thing in theThings)
{
var task = util.Process(thing)
.ContinueWith((t) => Console.Out.WriteLine($"Finished processing {thing.ThingId} with result {t.Result}"), TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith((t) => Console.Out.WriteLine($"Error on processing {thing.ThingId} with error {t.Exception.Message}"), TaskContinuationOptions.OnlyOnFaulted);
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
}
Since this wasn't possible I was thinking I would have to wrap each task call in a try catch inside the loop so I wouldn't stop the process but not wait on it there. I wasn't sure what the correct way.
Sometimes a solution is just staring you in the face, this would work wouldn't it?
public void ProccessAllTheThings()
{
var theThings = util.GetAllTheThings();
var tasks = new List<Task>();
foreach (var thing in theThings)
{
var task = util.Process(thing)
.ContinueWith((t) =>
{
if (t.Status == TaskStatus.RanToCompletion)
{
Console.Out.WriteLine($"Finished processing {thing.ThingId} with result {t.Result}");
}
else
{
Console.Out.WriteLine($"Error on processing {thing.ThingId} - {t.Exception.Message}");
}
});
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
}
What you did is to create a sequential chain of multiple tasks.
What you need to do is attach all your continuation tasks to the first one:
var firstTask = TaskThatReturnsString();
var t1 = firstTask.ContinueWith (…);
var t2 = firstTask.ContinueWith (…);
var t3 = firstTask.ContinueWith (…);
Then you need to wait for all the continuation tasks:
Task.WaitAll (t1, t2, t3);

Mixing async tasks with blocking sync task

I am writing a set of async tasks that go away an download and parse data, however I am running in to a bit of a blank with the next step where I am updating a database.
The issue is that for the sake of performance I am using a TableLock to load rather large datasets, so what I am wanting to do is have my import service wait for the first Task to return, start the import. Should another Task complete while the first import is running the process joins a queue and waits for the import service is complete for task 1.
eg.
Async
- Task1
- Task2
- Task3
Sync
- ImportService
RunAsync Tasks
Task3 returns first > ImportService.Import(Task3)
Task1 return, ImportService is still running. Wait()
ImportService.Complete() event
Task2 returns. Wait()
ImportService.Import(Task1)
ImportService.Complete() event
ImportService.Import(Task2)
ImportService.Complete() event
Hope this makes sense!
You can't really use await here, but you can wait on multiple tasks to complete:
var tasks = new List<Task)();
// start the tasks however
tasks.Add(Task.Run(Task1Function);
tasks.Add(Task.Run(Task2Function);
tasks.Add(Task.Run(Task2Function);
while (tasks.Count > 0)
{
var i = Task.WaitAny(tasks.ToArray()); // yes this is ugly but an array is required
var task = tasks[i];
tasks.RemoveAt(i);
ImportService.Import(task); // do you need to pass the task or the task.Result
}
Seems to me however that there should be a better option. You could let the tasks and the import run and add a lock on the ImportService part for instance:
// This is the task code doing whatever
....
// Task finishes and calls ImportService.Import
lock(typeof(ImportService)) // actually the lock should probably be inside the Import method
{
ImportService.Import(....);
}
There are several things bothering me with your requirements (including using a static ImportService, static classes are rarely a good idea), but without further details I can't provide better advice.
While this is likely not the most graceful solution, I would try launching the work tasks and have them place their output in a ConcurrentQueue. You could check the queue for work on a timer until all tasks are completed.
var rand = new Random();
var importedData = new List<string>();
var results = new ConcurrentQueue<string>();
var tasks = new List<Task<string>>
{
new Task<string>(() =>
{
Thread.Sleep(rand.Next(1000, 5000));
Debug.WriteLine("Task 1 Completed");
return "ABC";
}),
new Task<string>(() =>
{
Thread.Sleep(rand.Next(1000, 5000));
Debug.WriteLine("Task 2 Completed");
return "FOO";
}),
new Task<string>(() =>
{
Thread.Sleep(rand.Next(1000, 5000));
Debug.WriteLine("Task 3 Completed");
return "BAR";
})
};
tasks.ForEach(t =>
{
t.ContinueWith(r => results.Enqueue(r.Result));
t.Start();
});
var allTasksCompleted = new AutoResetEvent(false);
new Timer(state =>
{
var timer = (Timer) state;
string item;
if (!results.TryDequeue(out item))
return;
importedData.Add(item);
Debug.WriteLine("Imported " + item);
if (importedData.Count == tasks.Count)
{
timer.Dispose();
Debug.WriteLine("Completed.");
allTasksCompleted.Set();
}
}).Change(1000, 100);
allTasksCompleted.WaitOne();

Simplest way to run three methods in parallel in C#

I have three methods that I call to do some number crunching that are as follows
results.LeftFront.CalcAi();
results.RightFront.CalcAi();
results.RearSuspension.CalcAi(geom, vehDef.Geometry.LTa.TaStiffness, vehDef.Geometry.RTa.TaStiffness);
Each of the functions is independent of each other and can be computed in parallel with no dead locks.
What is the easiest way to compute these in parallel without the containing method finishing until all three are done?
See the TPL documentation. They list this sample:
Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());
So in your case this should just work:
Parallel.Invoke(
() => results.LeftFront.CalcAi(),
() => results.RightFront.CalcAi(),
() => results.RearSuspension.CalcAi(geom,
vehDef.Geometry.LTa.TaStiffness,
vehDef.Geometry.RTa.TaStiffness));
EDIT: The call returns after all actions have finished executing. Invoke() is does not guarantee that they will indeed run in parallel, nor does it guarantee the order in which the actions execute.
You can do this with tasks too (nicer if you later need Cancellation or something like results)
var task1 = Task.Factory.StartNew(() => results.LeftFront.CalcAi());
var task2 = Task.Factory.StartNew(() => results.RightFront.CalcAi());
var task3 = Task.Factory.StartNew(() =>results.RearSuspension.CalcAi(geom,
vehDef.Geometry.LTa.TaStiffness,
vehDef.Geometry.RTa.TaStiffness));
Task.WaitAll(task1, task2, task3);
In .NET 4, Microsoft introduced the Task Parallel Library which was designed to handle this kind of problem, see Parallel Programming in the .NET Framework.
To run parallel methods which are independent of each other ThreadPool.QueueUserWorkItem can also be used. Here is the sample method-
public static void ExecuteParallel(params Action[] tasks)
{
// Initialize the reset events to keep track of completed threads
ManualResetEvent[] resetEvents = new ManualResetEvent[tasks.Length];
// Launch each method in it's own thread
for (int i = 0; i < tasks.Length; i++)
{
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback((object index) =>
{
int taskIndex = (int)index;
// Execute the method
tasks[taskIndex]();
// Tell the calling thread that we're done
resetEvents[taskIndex].Set();
}), i);
}
// Wait for all threads to execute
WaitHandle.WaitAll(resetEvents);
}
More detail about this function can be found here:
http://newapputil.blogspot.in/2016/03/running-parallel-tasks-using.html
var task1 = SomeLongRunningTask();
var task2 = SomeOtherLongRunningTask();
await Task.WhenAll(task1, task2);
The benefit of this over Task.WaitAll is that this will release the thread and await the completion of the two tasks.

Is there any way to start task using ContinueWith task?

My code:
var r = from x in new Task<int>(() => 1)
from y in new Task<int>(() => x + 1)
select y;
r.ContinueWith(x => Console.WriteLine(x.Result)).Start();
or
new Task<int>(() => 1)
.ContinueWith(x => x.Result + 1)
.ContinueWith(x => Console.WriteLine(x.Result))
.Start();
Exception:
Start may not be called on a continuation task.
So I need to start the first task. Is there any way to call last task Start method to run all tasks?
Any reason not to use Task.Factory.StartNewmsdn, ms docs for the first task? Yes, it's inconsistent - but it's fundamentally a different kind of task, in terms of being started explicitly rather than just as a continuation.
I'm not really sure what's wrong with just writing this:
var t1 = new Task<int>(() => 1)
var r = from x in t1
from y in new Task<int>(() => x + 1)
select y;
r.ContinueWith(x => Console.WriteLine(x.Result));
t1.Start();
or this:
var t = new Task<int>(() => 1)
t.ContinueWith(x => x.Result + 1)
.ContinueWith(x => Console.WriteLine(x.Result))
t.Start();
That directly expresses what you actually want to do. (It's the initial task that you want to kick off. So what's wrong with invoking Start on that initial task?) Why are you looking for a syntax that obscures that?
EDIT: fixed first example...
EDIT 2 to add:
So I realise now that LinqToTasks expects task selectors to return running tasks. So the second from clause in your first example returns a task that nothing will ever run. So what you actually need is this:
var t1 = new Task<int>(() => 1);
var r = from x in t1
from y in Task<int>.Factory.StartNew(() => x + 1)
select y;
r.ContinueWith(x => Console.WriteLine(x.Result));
t1.Start();
Nothing else is going to call Start on the tasks produced in these from clauses. Since the relevant selectors don't actually get executed until the previous task completes, you're still in control of when to kick off the root task.
That appears to work, but it's pretty ugly. But that appears to be how LinqToTasks is designed... I think I'd stick with the regular function call syntax.
The problem is that selecting tasks with LINQ Will Only Create an Expression Tree!
So here's what you need to do:
var query =
from i in Enumerable.Range(1, 4)
let task = Task.Factory.StartNew(() => Tuple.Create(i, IsPrime(i))) // put a breakpoint here
select task.ContinueWith(delegate {
Console.WriteLine("{0} {1} prime.", _.Result.Item1, _.Result.Item2 ? "is" : "is not");
});
// breakpoint never hit yet
query.ToArray(); // breakpoint hit here 4 times
// all tasks are now running and continuations will start
TaskEx.Await(query.ToArray()); // breakpoint hit 4 more times!!
I had the same problem today. I wanted to create a wrapper task that handles an error from an inner task. This is what I came up with:
var yourInitialTask = new Task(delegate
{
throw e;
});
var continuation = task.ContinueWith(t =>
{
if (task.IsCanceled)
{
Debug.WriteLine("IsCanceled: " + job.GetType());
}
else if (task.IsFaulted)
{
Debug.WriteLine("IsFaulted: " + job.GetType());
}
else if (task.IsCompleted)
{
Debug.WriteLine("IsCompleted: " + job.GetType());
}
}, TaskContinuationOptions.ExecuteSynchronously); //or consider removing execute synchronously if your continuation task is going to take long
var wrapper = new Task(() =>
{
task.Start();
continuation.Wait();
});
return wrapper;
The key features here are that
-the continuation part runs after the original task, as you want
-the wrapper is Startable. Continuation tasks created with ContineWith() are nto Startable.
A less key feature of this example, is that the exception is being logged and discarded (solves my problem, not yours). You might want to be doing something different when exceptions occur in the continuation such as rethrow it as an exception of the current task, so that it bubbles out.
As far as I'm aware, there's no sensible way to compose non-started tasks provided by the framework. The simplest solution I can think of is extension methods. Here are some examples which you could build on if you need this functionality.
Warning: Just as with passing around and composing tons of lambdas, if you find yourself needing these, it often means you are missing a type in your design that would simplify your code. Ask yourself what you gained by creating the subtasks.
/// <summary>
/// Compose tasks without starting them.
/// Waiting on the returned task waits for both components to complete.
/// An exception in the first task will stop the second task running.
/// </summary>
public static class TaskExtensions
{
public static Task FollowedBy(this Task first, Task second)
{
return FollowedBy(first,
() =>
{
second.Start();
second.Wait();
});
}
public static Task FollowedBy(this Task first, Action second)
{
return new Task(
() =>
{
if (first.Status == TaskStatus.Created) first.Start();
first.Wait();
second();
});
}
public static Task FollowedBy<T>(this Task first, Task<T> second)
{
return new Task<T>(
() =>
{
if (first.Status == TaskStatus.Created) first.Start();
first.Wait();
second.Start();
return second.Result;
});
}
public static Task FollowedBy<T>(this Task<T> first, Action<T> second)
{
return new Task(
() =>
{
if (first.Status == TaskStatus.Created) first.Start();
var firstResult = first.Result;
second(firstResult);
});
}
public static Task<TSecond> FollowedBy<TFirst, TSecond>(this Task<TFirst> first, Func<TFirst, TSecond> second)
{
return new Task<TSecond>(
() =>
{
if (first.Status == TaskStatus.Created) first.Start();
return second(first.Result);
});
}
}
The answer is simple. ContinueWith is automatically start task. And first task need to be running.
var r= Task<int>.Run<int>( () => 1 )
.ContinueWith<int>( x => x.Result + 1 )
.ContinueWith( x => Console.WriteLine( x.Result ) );
ContinueWith return task that start with checking previous task is done or not. This code work in the same way like below code
var firstTask = new Task<int>( () => 1 );
firstTask.Start();
var firstawaiter = firstTask.GetAwaiter();
var secondTask = new Task<int>( x => (int)x + 1 , firstawaiter.GetResult());
firstawaiter.OnCompleted( () =>
{
secondTask.Start();
} );
var secondawaiter = secondTask.GetAwaiter();
var thirdTask = new Task( x => Console.WriteLine( x ) , secondawaiter.GetResult());
secondawaiter.OnCompleted( () =>
{
thirdTask.Start();
} );
So, If first task is not completed, next task will not be started.
And you not need to start continuewith block .

Categories