How to wait after the first task RanToCompletion - c#

I was trying to use Task.WaitAny to wait a bunch of tasks but what I really want is to wait for the first RanToCompletion task instead of Canceled tasks.
So when I have a bunch tasks whose status are like:
0 Canceled;1 Canceled;2 Canceled;3 Canceled;4 Canceled;5 RanToCompletion;
Ideally I would want Task.WaitAny to return 5 but what it returns is 0.
How should I wait for the first RanToCompletion task?

There is nothing available out of the box. We need to write some helper method as noted in comments.
Here's an implementation using TaskCompletionSource.
public class MyTask
{
private readonly TaskCompletionSource<Task> completionSource = new TaskCompletionSource<Task>();
private readonly Task[] tasks;
private int numberOfTasks;
private MyTask(Task[] tasks)
{
if (tasks.Length == 0)
{
throw new ArgumentException("No tasks");
}
this.tasks = tasks;
this.numberOfTasks= tasks.Length;
}
private int WaitAnyInternal()
{
foreach (var task in tasks)
{
task.ContinueWith(task1 => completionSource.TrySetResult(task1), TaskContinuationOptions.OnlyOnRanToCompletion);
}
foreach (var task in tasks)
{
task.ContinueWith(task1 =>
{
if (Interlocked.Decrement(ref numberOfTasks) == 0)
{
completionSource.SetCanceled();
}
}, TaskContinuationOptions.NotOnRanToCompletion);
}
try
{
completionSource.Task.Wait();
}
catch (AggregateException ex)
{
if (ex.Flatten().InnerExceptions.OfType<OperationCanceledException>().Any())
{
return -1;
}
}
return Array.IndexOf(tasks, completionSource.Task.Result);
}
public static int WaitAnyRanToCompletion(params Task[] tasks)
{
return new MyTask(tasks).WaitAnyInternal();
}
}
Then use it as:
var task1 = Task.Run(() =>
{
Thread.Sleep(1000);
throw new Exception();
});//Faulted task
var task2 = Task.Run(() =>
{
Thread.Sleep(5000);
});//Will complete first
var task3 = Task.Delay(10000);//Will complete, but not first
int index = MyTask.WaitAnyRanToCompletion(task1, task2, task3);
//Index will be 1, which means task2

Related

A simple data producer/consumer implementation using IProducerConsumerCollection? [duplicate]

I would like to await on the result of BlockingCollection<T>.Take() asynchronously, so I do not block the thread. Looking for anything like this:
var item = await blockingCollection.TakeAsync();
I know I could do this:
var item = await Task.Run(() => blockingCollection.Take());
but that kinda kills the whole idea, because another thread (of ThreadPool) gets blocked instead.
Is there any alternative?
There are four alternatives that I know of.
The first is Channels, which provides a threadsafe queue that supports asynchronous Read and Write operations. Channels are highly optimized and optionally support dropping some items if a threshold is reached.
The next is BufferBlock<T> from TPL Dataflow. If you only have a single consumer, you can use OutputAvailableAsync or ReceiveAsync, or just link it to an ActionBlock<T>. For more information, see my blog.
The last two are types that I created, available in my AsyncEx library.
AsyncCollection<T> is the async near-equivalent of BlockingCollection<T>, capable of wrapping a concurrent producer/consumer collection such as ConcurrentQueue<T> or ConcurrentBag<T>. You can use TakeAsync to asynchronously consume items from the collection. For more information, see my blog.
AsyncProducerConsumerQueue<T> is a more portable async-compatible producer/consumer queue. You can use DequeueAsync to asynchronously consume items from the queue. For more information, see my blog.
The last three of these alternatives allow synchronous and asynchronous puts and takes.
...or you can do this:
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class AsyncQueue<T>
{
private readonly SemaphoreSlim _sem;
private readonly ConcurrentQueue<T> _que;
public AsyncQueue()
{
_sem = new SemaphoreSlim(0);
_que = new ConcurrentQueue<T>();
}
public void Enqueue(T item)
{
_que.Enqueue(item);
_sem.Release();
}
public void EnqueueRange(IEnumerable<T> source)
{
var n = 0;
foreach (var item in source)
{
_que.Enqueue(item);
n++;
}
_sem.Release(n);
}
public async Task<T> DequeueAsync(CancellationToken cancellationToken = default(CancellationToken))
{
for (; ; )
{
await _sem.WaitAsync(cancellationToken);
T item;
if (_que.TryDequeue(out item))
{
return item;
}
}
}
}
Simple, fully functional asynchronous FIFO queue.
Note: SemaphoreSlim.WaitAsync was added in .NET 4.5 before that, this was not all that straightforward.
Here is a very basic implementation of a BlockingCollection that supports awaiting, with lots of missing features. It uses the AsyncEnumerable library, that makes asynchronous enumeration possible for C# versions older than 8.0.
public class AsyncBlockingCollection<T>
{ // Missing features: cancellation, boundedCapacity, TakeAsync
private Queue<T> _queue = new Queue<T>();
private SemaphoreSlim _semaphore = new SemaphoreSlim(0);
private int _consumersCount = 0;
private bool _isAddingCompleted;
public void Add(T item)
{
lock (_queue)
{
if (_isAddingCompleted) throw new InvalidOperationException();
_queue.Enqueue(item);
}
_semaphore.Release();
}
public void CompleteAdding()
{
lock (_queue)
{
if (_isAddingCompleted) return;
_isAddingCompleted = true;
if (_consumersCount > 0) _semaphore.Release(_consumersCount);
}
}
public IAsyncEnumerable<T> GetConsumingEnumerable()
{
lock (_queue) _consumersCount++;
return new AsyncEnumerable<T>(async yield =>
{
while (true)
{
lock (_queue)
{
if (_queue.Count == 0 && _isAddingCompleted) break;
}
await _semaphore.WaitAsync();
bool hasItem;
T item = default;
lock (_queue)
{
hasItem = _queue.Count > 0;
if (hasItem) item = _queue.Dequeue();
}
if (hasItem) await yield.ReturnAsync(item);
}
});
}
}
Usage example:
var abc = new AsyncBlockingCollection<int>();
var producer = Task.Run(async () =>
{
for (int i = 1; i <= 10; i++)
{
await Task.Delay(100);
abc.Add(i);
}
abc.CompleteAdding();
});
var consumer = Task.Run(async () =>
{
await abc.GetConsumingEnumerable().ForEachAsync(async item =>
{
await Task.Delay(200);
await Console.Out.WriteAsync(item + " ");
});
});
await Task.WhenAll(producer, consumer);
Output:
1 2 3 4 5 6 7 8 9 10
Update: With the release of C# 8, asynchronous enumeration has become a build-in language feature. The required classes (IAsyncEnumerable, IAsyncEnumerator) are embedded in .NET Core 3.0, and are offered as a package for .NET Framework 4.6.1+ (Microsoft.Bcl.AsyncInterfaces).
Here is an alternative GetConsumingEnumerable implementation, featuring the new C# 8 syntax:
public async IAsyncEnumerable<T> GetConsumingEnumerable()
{
lock (_queue) _consumersCount++;
while (true)
{
lock (_queue)
{
if (_queue.Count == 0 && _isAddingCompleted) break;
}
await _semaphore.WaitAsync();
bool hasItem;
T item = default;
lock (_queue)
{
hasItem = _queue.Count > 0;
if (hasItem) item = _queue.Dequeue();
}
if (hasItem) yield return item;
}
}
Note the coexistence of await and yield in the same method.
Usage example (C# 8):
var consumer = Task.Run(async () =>
{
await foreach (var item in abc.GetConsumingEnumerable())
{
await Task.Delay(200);
await Console.Out.WriteAsync(item + " ");
}
});
Note the await before the foreach.
If you don't mind a little hack, you can try these extensions.
public static async Task AddAsync<TEntity>(
this BlockingCollection<TEntity> Bc, TEntity item, CancellationToken abortCt)
{
while (true)
{
try
{
if (Bc.TryAdd(item, 0, abortCt))
return;
else
await Task.Delay(100, abortCt);
}
catch (Exception)
{
throw;
}
}
}
public static async Task<TEntity> TakeAsync<TEntity>(
this BlockingCollection<TEntity> Bc, CancellationToken abortCt)
{
while (true)
{
try
{
TEntity item;
if (Bc.TryTake(out item, 0, abortCt))
return item;
else
await Task.Delay(100, abortCt);
}
catch (Exception)
{
throw;
}
}
}

Use SemaphoreSlim when generating array of tasks in LINQ lambda expression

I am using a LINQ lambda expression to generate an array of tasks and add them to a list of tasks. I want to implement a Semaphore to limit the number of tasks in process at a given point in time.
Here is code that represents what I currently have:
class Test {
private List<Task> tasks;
public void Start(){
tasks = new List<Task>();
AddTasks();
}
private void AddTasks(){
tasks.AddRange(
items
.Where(x => x.InProcess == false)
.Select( async (item) = > {
await DoWork(item);
})
.ToArray()
);
}
}
I want to achieve something similar to:
class Test {
private List<Task> tasks;
private SemaphoreSlim semaphore ;
public void Start(){
tasks = new List<Task>();
semaphore = new SemaphoreSlim(5);
AddTasks();
}
private void AddTasks(){
tasks.AddRange(
items
.Where(x => x.InProcess == false)
.Select( async (item) = > {
await semaphore.AwaitAsync();
try
{
await DoWork(item);
}
catch (System.Exception)
{
throw;
}
finally {
semaphore.Release();
}
})
.ToArray()
);
}
}
But I do not think this will work correctly, as the semaphore is inside of the task. How can I use the semaphore as part of the LINQ query to stall generating new tasks until the semaphore is awaited?
You can try this code. It should work as you expected but I haven't tried it. And don't forget to call await Task.WhenAll(tasks) when it's done and you need to get result.
private void AddTasks()
{
tasks.AddRange(items
.Where(x => x.InProcess == false)
.Select(AddTaskAsync)
.ToArray());
//later await Task.WhenAll(tasks);
}
private async Task AddTaskAsync(YourClass item)
{
await semaphore.WaitAsync();
try
{
await DoWork(item);
}
finally
{
semaphore.Release();
}
}
My example code did accomplish what I intended. Using the semaphore inside of the Task didn't cause any problems. It prevented the Task from running, which was the goal.

How to create never ending DataFlow Mesh with exception handling?

I am creating a Task processor which uses TPL DataFlow. I will follow a producer consumer model where in Producer produces some items to be processed once in a while and consumers keep waiting for new items to arrive. Here is my code:
async Task Main()
{
var runner = new Runner();
CancellationTokenSource cts = new CancellationTokenSource();
Task runnerTask = runner.ExecuteAsync(cts.Token);
await Task.WhenAll(runnerTask);
}
public class Runner
{
public async Task ExecuteAsync(CancellationToken cancellationToken) {
var random = new Random();
ActionMeshProcessor processor = new ActionMeshProcessor();
await processor.Init(cancellationToken);
while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(1)); // wait before enqueuing more
int[] items = GetItems(random.Next(3, 7));
await processor.ProcessBlockAsync(items);
}
}
private int[] GetItems(int count)
{
Random randNum = new Random();
int[] arr = new int[count];
for (int i = 0; i < count; i++)
{
arr[i] = randNum.Next(10, 20);
}
return arr;
}
}
public class ActionMeshProcessor
{
private TransformBlock<int, int> Transformer { get; set; }
private ActionBlock<int> CompletionAnnouncer { get; set; }
public async Task Init(CancellationToken cancellationToken)
{
var options = new ExecutionDataflowBlockOptions
{
CancellationToken = cancellationToken,
MaxDegreeOfParallelism = 5,
BoundedCapacity = 5
};
this.Transformer = new TransformBlock<int, int>(async input => {
await Task.Delay(TimeSpan.FromSeconds(1)); //donig something complex here!
if (input > 15)
{
throw new Exception($"I can't handle this number: {input}");
}
return input + 1;
}, options);
this.CompletionAnnouncer = new ActionBlock<int>(async input =>
{
Console.WriteLine($"Completed: {input}");
await Task.FromResult(0);
}, options);
this.Transformer.LinkTo(this.CompletionAnnouncer);
await Task.FromResult(0); // what do I await here?
}
public async Task ProcessBlockAsync(int[] arr)
{
foreach (var item in arr)
{
await this.Transformer.SendAsync(item); // await if there are no free slots
}
}
}
I added a condition check above to throw an exception to mimic an exceptional case.
Here are my questions:
What is the best way I can handle exceptions in the above mesh without bringing the whole mesh down?
Is there a better way to initialize/start/continue a never ending DataFlow mesh?
Where do I await Completion?
I have looked in to this similar question
Exceptions
There's nothing asynchronous in your init it could be a standard synchronous constructor. You can handle exceptions in your mesh without taking the mesh down with a simple try catch in the lamda you provide to the block. You can then handle that case by either filtering the result from your mesh or ignoring the result in the following blocks. Below is an example of filtering. For the simple case of an int you can use an int? and filter out any value that was null or of course you could set any type of magic indicator value if you like. If your actually passing around a reference type you can either push out null or mark the data item as dirty in way that can be examined by the predicate on your link.
public class ActionMeshProcessor {
private TransformBlock<int, int?> Transformer { get; set; }
private ActionBlock<int?> CompletionAnnouncer { get; set; }
public ActionMeshProcessor(CancellationToken cancellationToken) {
var options = new ExecutionDataflowBlockOptions {
CancellationToken = cancellationToken,
MaxDegreeOfParallelism = 5,
BoundedCapacity = 5
};
this.Transformer = new TransformBlock<int, int?>(async input => {
try {
await Task.Delay(TimeSpan.FromSeconds(1)); //donig something complex here!
if (input > 15) {
throw new Exception($"I can't handle this number: {input}");
}
return input + 1;
} catch (Exception ex) {
return null;
}
}, options);
this.CompletionAnnouncer = new ActionBlock<int?>(async input =>
{
if (input == null) throw new ArgumentNullException("input");
Console.WriteLine($"Completed: {input}");
await Task.FromResult(0);
}, options);
//Filtering
this.Transformer.LinkTo(this.CompletionAnnouncer, x => x != null);
this.Transformer.LinkTo(DataflowBlock.NullTarget<int?>());
}
public async Task ProcessBlockAsync(int[] arr) {
foreach (var item in arr) {
await this.Transformer.SendAsync(item); // await if there are no free slots
}
}
}
Completion
You can expose Complete() and Completion from your processor and use those to await the completion when your app shutsdown, assuming thats the only time you'd shutdown the mesh. Also, make sure you propagate completion through your links properly.
//Filtering
this.Transformer.LinkTo(this.CompletionAnnouncer, new DataflowLinkOptions() { PropagateCompletion = true }, x => x != null);
this.Transformer.LinkTo(DataflowBlock.NullTarget<int?>());
}
public void Complete() {
Transformer.Complete();
}
public Task Completion {
get { return CompletionAnnouncer.Completion; }
}
Then, based on your sample the most likely place for completion is outside the loop driving your processing:
public async Task ExecuteAsync(CancellationToken cancellationToken) {
var random = new Random();
ActionMeshProcessor processor = new ActionMeshProcessor();
await processor.Init(cancellationToken);
while (!cancellationToken.IsCancellationRequested) {
await Task.Delay(TimeSpan.FromSeconds(1)); // wait before enqueuing more
int[] items = GetItems(random.Next(3, 7));
await processor.ProcessBlockAsync(items);
}
//asuming you don't intend to throw from cancellation
processor.Complete();
await processor.Completion();
}

Ignore the Tasks throwing Exceptions at Task.WhenAll and get only the completed results

I am working on a Task parallel problem that I have many Tasks that may or may not throw Exception.
I want to process all the tasks that finishes properly and log the rest. The Task.WhenAll propage the Task exception without allowing me to gather the rest results.
static readonly Task<string> NormalTask1 = Task.FromResult("Task result 1");
static readonly Task<string> NormalTask2 = Task.FromResult("Task result 2");
static readonly Task<string> ExceptionTk = Task.FromException<string>(new Exception("Bad Task"));
var results = await Task.WhenAll(new []{ NormalTask1,NormalTask2,ExceptionTk});
The Task.WhenAll with throw the Exception of ExcceptionTk ignoring the rest results. How I can get the results ignoring the Exception and log the exception at same time?
I could wrap the task into another task that try{...}catch(){...} the internal exception but I don't have access to them and I hope I will not have to add this overhead.
You can create a method like this to use instead of Task.WhenAll:
public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks)
{
return Task.WhenAll(
tasks.Select(
task => task.ContinueWith(
t => t.IsFaulted
? new ResultOrException<T>(t.Exception)
: new ResultOrException<T>(t.Result))));
}
public class ResultOrException<T>
{
public ResultOrException(T result)
{
IsSuccess = true;
Result = result;
}
public ResultOrException(Exception ex)
{
IsSuccess = false;
Exception = ex;
}
public bool IsSuccess { get; }
public T Result { get; }
public Exception Exception { get; }
}
Then you can check each result to see if it was successful or not.
EDIT: the code above doesn't handle cancellation; here's an alternative implementation:
public Task<ResultOrException<T>[]> WhenAllOrException<T>(IEnumerable<Task<T>> tasks)
{
return Task.WhenAll(tasks.Select(task => WrapResultOrException(task)));
}
private async Task<ResultOrException<T>> WrapResultOrException<T>(Task<T> task)
{
try
{
var result = await task;
return new ResultOrException<T>(result);
}
catch (Exception ex)
{
return new ResultOrException<T>(ex);
}
}
You can get the result of each successfully completed Task<TResult> from its property Result.
var normalTask1 = Task.FromResult("Task result 1");
var normalTask2 = Task.FromResult("Task result 2");
var exceptionTk = Task.FromException<string>(new Exception("Bad Task"));
Task<string>[] tasks = new[] { normalTask1, normalTask2, exceptionTk };
Task whenAll = Task.WhenAll(tasks);
try
{
await whenAll;
}
catch
{
if (whenAll.IsFaulted) // There is also the possibility of being canceled
{
foreach (var ex in whenAll.Exception.InnerExceptions)
{
Console.WriteLine(ex); // Log each exception
}
}
}
string[] results = tasks
.Where(t => t.IsCompletedSuccessfully)
.Select(t => t.Result)
.ToArray();
Console.WriteLine($"Results: {String.Join(", ", results)}");
Output:
System.Exception: Bad Task
Results: Task result 1, Task result 2
You can add HOC with exception handling and then check success.
class Program
{
static async Task Main(string[] args)
{
var itemsToProcess = new[] { "one", "two" };
var results = itemsToProcess.ToDictionary(x => x, async (item) =>
{
try
{
var result = await DoAsync();
return ((Exception)null, result);
}
catch (Exception ex)
{
return (ex, (object)null);
}
});
await Task.WhenAll(results.Values);
foreach(var item in results)
{
Console.WriteLine(item.Key + (await item.Value).Item1 != null ? " Failed" : "Succeed");
}
}
public static async Task<object> DoAsync()
{
await Task.Delay(10);
throw new InvalidOperationException();
}
}

Stop to finish all threads before starting new threads c# 4.0

I am creating many threads using below method
Task.Factory.StartNew(() =>
{
//do some task here
});
In some point of time I want to execute a method but before that I want to
Ensure that all currently running threads are get finished.
Ensure if there is any call to create new thread should wait and not lost.
After my method is executed start all waiting threads.
Any good solution will be appreciated.
Thanks in advance
--------------------Edited Code-----------------------
for (int i = 0; i < 10; i++)
{
Task.Factory.StartNew(() =>
{
Console.WriteLine("First Thread # " + DateTime.Now.ToString());
});
}
When we reach to this call this should check any pending tasks before executing
Console.WriteLine("*******************Called Another Method***********************");
When above is being executed and another request is coming same as below then it should only start after above line (in my case method) is executed.
for (int i = 0; i < 10; i++)
{
Task.Factory.StartNew(() =>
{
Console.WriteLine("Second Thread # " + DateTime.Now.ToString());
});
}
I think what you really want is to implement some sort of Queue that executes the work in a single thread. Here's some minimal implementation (untested!)
class QueuedWorker
{
ConcurrentQueue<Action> queue = new ConcurrentQueue<Action>();
ManualResetEvent waiter = new ManualResetEvent(false);
Thread workerThread;
public QueuedWorker()
{
workerThread = new Thread(ThreadWorker);
workerThread.Start();
}
private void ThreadWorker()
{
Action nextTask;
while(true)
{
while(queue.TryDequeue(out nextTask))
{
// run the queued task
nextTask();
}
waiter.WaitOne();
waiter.Reset();
}
}
public void Enqueue(Action item)
{
queue.Enqueue(item);
waiter.Set();
}
}
I solved the problem my self by storing tasks created into a list and applying lock on it.
class Program
{
static List<Task> taskList = new List<Task>();
static void Main(string[] args)
{
Task.Factory.StartNew(() => { StartTasks("First"); });
Task.Factory.StartNew(() => { LoadMethod(); });
Task.Factory.StartNew(() => { StartTasks("Second"); StartTasks("Third"); });
Task.Factory.StartNew(() => { LoadMethod(); });
Task.Factory.StartNew(() => { StartTasks("Four"); });
Task.Factory.StartNew(() => { LoadMethod(); });
Task.Factory.StartNew(() => { StartTasks("Five"); StartTasks("Six"); StartTasks("Seven"); StartTasks("Eight"); });
Task.Factory.StartNew(() => { LoadMethod(); });
Task.Factory.StartNew(() => { StartTasks("Nine"); StartTasks("Ten"); });
Task.Factory.StartNew(() => { LoadMethod(); });
Console.WriteLine("Execution is completed !");
Console.ReadKey();
}
public static void LoadMethod()
{
// Lock and wait to not allow any thead to modify the list
lock (taskList)
{
if (taskList.Any())
{
Task.WaitAll(taskList.ToArray());
}
Debug.WriteLine("*******************Called Another Method***********************");
taskList.Clear();
}
}
public static void StartTasks(string taskName)
{
lock (taskList)
{
for (int i = 0; i < 10; i++)
{
var t = new Task(() =>
{
Debug.WriteLine(taskName + " # " + DateTime.Now.ToString());
//System.Threading.Thread.Sleep(500);
});
taskList.Add(t);
}
Task.Factory.StartNew(() => taskList.ForEach(task =>
{
if (task.Status == TaskStatus.Created)
{
task.Start();
}
}), TaskCreationOptions.AttachedToParent);
}
}
}

Categories

Resources