Skip to content

Instantly share code, notes, and snippets.

@JimBobSquarePants
Created July 10, 2018 08:22
Show Gist options
  • Save JimBobSquarePants/ec7e267b797451271747efd87b5e80ac to your computer and use it in GitHub Desktop.
Save JimBobSquarePants/ec7e267b797451271747efd87b5e80ac to your computer and use it in GitHub Desktop.
Attempt at demoing returning only completed tasks from a collection.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace TaskTest
{
class Program
{
private static Random r = new Random();
static async Task Main(string[] args)
{
var tasks = new Task<IEnumerable<int>>[] { ExternalTask(), ExternalTask(), ExternalTask(), ExternalTask(), ExternalTask() };
var t2 = await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(3000));
var completedResults = tasks
.Where(t => t.Status == TaskStatus.RanToCompletion)
.Select(t => t.Result)
.ToList();
foreach (var item in completedResults)
{
Console.WriteLine($"Task completed with {item.First()} delay.");
}
Console.ReadLine();
}
private static Task<IEnumerable<int>> ExternalTask()
{
int delay = r.Next(0, 6000);
Task.Delay(delay);
var enumerable = Enumerable.Repeat(delay, 6);
return Task.FromResult(enumerable);
}
}
}
@JimBobSquarePants
Copy link
Author

The above doesn't do what I expected.

I assumed that the the completedResults enumerable would only contain a subset of the tasks enumerable since some will run for longer than the Task.Delay(3000) task but it's returning all of them.

What have I done wrong?

@bruno-garcia
Copy link

bruno-garcia commented Jul 10, 2018

Await Task.Delay: ExternalTask is running synchronously. It kicks off a task delay but doesn't await on it.
You could replace that with a Thread.Sleep instead or make the method async and await on Task.Delay . Obviously in production apps Thread.Sleep would get Ben Adams to come after you.

@JimBobSquarePants
Copy link
Author

Complete working demo. await all the things!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace TaskDemo
{
    class Program
    {
        private static Random r = new Random();
        private const int delay = 3000;

        static async Task Main(string[] args)
        {
            var tasks = new Task<IEnumerable<int>>[] { ExternalTask(), ExternalTask(), ExternalTask(), ExternalTask(), ExternalTask() };

            // Gather the results that complete within the timespan interval.
            var completedResults = await WhenAll(tasks, TimeSpan.FromMilliseconds(3000));

            Console.WriteLine($"Completed Tasks within {delay}:");
            foreach (var item in completedResults)
            {
                Console.WriteLine($"Task completed with {item.First()} milliseconds delay.");
            }

            Console.ReadLine();
        }

        private async static Task<IEnumerable<int>> ExternalTask()
        {
            // Randomly delay the task to anywhere between 0 and 2x the delay
            int milliseconds = r.Next(0, 2 * delay);
            Console.WriteLine($"Task will take {milliseconds} milliseconds.");

            await Task.Delay(milliseconds);
            var enumerable = Enumerable.Repeat(milliseconds, 6);
            return enumerable;
        }

        /// <summary>
        /// Creates a task that will complete when <see cref="Task{TResult[]}"/> the timeout interval has passed. 
        /// </summary>
        /// <typeparam name="TResult">The type of result.</typeparam>
        /// <param name="tasks">The enumerable of tasks to attempt to complete.</param>
        /// <param name="timeout">The timeout.</param>
        /// <returns>The <paramref name="tasks"/> completed within the timespan limit.</returns>
        private static async Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks, TimeSpan timeout)
        {
            await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(timeout));
            return tasks
                  .Where(t => t.Status == TaskStatus.RanToCompletion)
                  .Select(t => t.Result)
                  .ToArray();
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment