Cold Tasks and TaskExtensions.Unwrap - c#

I've got a caching class that uses cold (unstarted) tasks to avoid running the expensive thing multiple times.
public class AsyncConcurrentDictionary<TKey, TValue> : System.Collections.Concurrent.ConcurrentDictionary<TKey, Task<TValue>>
{
internal Task<TValue> GetOrAddAsync(TKey key, Task<TValue> newTask)
{
var cachedTask = base.GetOrAdd(key, newTask);
if (cachedTask == newTask && cachedTask.Status == TaskStatus.Created) // We won! our task is now the cached task, so run it
cachedTask.Start();
return cachedTask;
}
}
This works great right up until your task is actually implemented using C#5's await, ala
cache.GetOrAddAsync("key", new Task(async () => {
var r = await AsyncOperation();
return r.FastSynchronousTransform();
}));)`
Now it looks like TaskExtensions.Unwrap() does exactly what I need by turning Task<Task<T>> into a Task<T>, but it seems that wrapper it returns doesn't actually support Start() - it throws an exception.
TaskCompletionSource (my go to for slightly special Task needs) doesn't seem to have any facilities for this sort of thing either.
Is there an alternative to TaskExtensions.Unwrap() that supports "cold tasks"?

All you need to do is to keep the Task before unwrapping it around and start that:
public Task<TValue> GetOrAddAsync(TKey key, Func<Task<TValue>> taskFunc)
{
Task<Task<TValue>> wrappedTask = new Task<Task<TValue>>(taskFunc);
Task<TValue> unwrappedTask = wrappedTask.Unwrap();
Task<TValue> cachedTask = base.GetOrAdd(key, unwrappedTask);
if (cachedTask == unwrappedTask)
wrappedTask.Start();
return cachedTask;
}
Usage:
cache.GetOrAddAsync(
"key", async () =>
{
var r = await AsyncOperation();
return r.FastSynchronousTransform();
});

Related

How to return a Task<T> without await

Is it possible to return a task from a method which first calls multiple Task<T> returning methods and then returns some type that includes the results from previous calls without using await?
For example, the below is straight forward:
public Task<SomeType> GetAsync() => FirstOrDefaultAsync();
However, I would like to do something like this:
public Task<SomeType> GetAsync()
{
var list = GetListAsync(); // <-- Task<List<T>>
var count = GetCountAsync(); // <-- Task<int>
return new SomeType // <-- Obviously compiler error
{
List /* <-- List<T> */ = list, // <-- Also compiler error
Count /* <-- int */ = count, // <-- Also compiler error
};
}
Is it possible to do this without having to write:
public async Task<SomeType> GetAsync()
{
return new Type2
{
List = await GetListAsync(),
Count = await GetCountAsync(),
};
}
Frankly, the version already in the question is correct:
public async Task<SomeType> GetAsync()
{
return new Type2
{
List = await GetListAsync(),
Count = await GetCountAsync(),
};
}
I realize you asked "without using await", but: the hacks to avoid the await are suboptimal; in particular, you should almost never use ContinueWith - that is the legacy API, and the Task implementation is now optimized for await, not ContinueWith.
As for:
Because I read that having multiple await is bad for performance. I try to await on last call
No; once you have one incomplete await, it pretty much doesn't matter how many more you have - they're effectively free. The issue of having one vs zero incomplete await is comparable to the ContinueWith, so : you're not gaining anything by avoiding the await.
Conclusion: just use the await. It is simpler and more direct, and the internals are optimized for it.
As a minor optimization, you might want to add ConfigureAwait(false), i.e.
public async Task<SomeType> GetAsync()
{
return new Type2
{
List = await GetListAsync().ConfigureAwait(false),
Count = await GetCountAsync().ConfigureAwait(false),
};
}
Or if they should run concurrently, and the implementation supports it:
public Task<SomeType> GetAsync()
{
var list = GetListAsync();
var count = GetCountAsync();
return new SomeType
{
List = await list.ConfigureAwait(false),
Count = await count.ConfigureAwait(false),
};
}
You can use Task.WhenAll together with Task.ContinueWith.
public Task<SomeType> GetAsync()
{
var list = GetListAsync();
var count = GetCountAsync();
return Task.WhenAll(list, count).ContinueWith(_ => new Type2
{
List = list.Result,
Count = count.Result,
});
}
Edit
As suggested in comments, you're better off just using await. I also advice to read the post linked by GSerg - Performance of Task.ContinueWith in non-async method vs. using async/await
The problem is that the Task.WhenAll method does not accept tasks with different result types. All tasks must be of the same type. Fortunately this is easy to fix. The WhenAll variant bellow waits for two tasks with different types, and returns a task with the combined results.
public static Task<TResult> WhenAll<T1, T2, TResult>(
Task<T1> task1, Task<T2> task2, Func<T1, T2, TResult> factory)
{
return Task.WhenAll(task1, task2).ContinueWith(t =>
{
var tcs = new TaskCompletionSource<TResult>();
if (t.IsFaulted)
{
tcs.SetException(t.Exception.InnerExceptions);
}
else if (t.IsCanceled)
{
tcs.SetCanceled();
}
else
{
tcs.SetResult(factory(task1.Result, task2.Result));
}
return tcs.Task;
}, default, TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default).Unwrap();
}
It can be used like this:
public Task<SomeType> GetAsync()
{
return WhenAll(GetListAsync(), GetCountAsync(),
(list, count) => new SomeType { List = list, Count = count });
}
The advantage over the other solutions is at the handling of exceptions. If both GetListAsync and GetCountAsync fail, the task returned from GetAsync will preserve both exceptions in a shallow AggregateException (not nested in another AggregateException).
Btw this answer is inspired by a Stephen Cleary's answer here.

Avoiding resource leaks with `FirstAsync` observer tasks that never happen

I have some software with an event-based networking protocol for control which is using a IObservable<Event> for handling in bound messages.
In many cases a sent message will expect a specific response (or sequence, such as to report progress). In order to not potentially miss the response a task is being set up in advance with FirstAsync and ToTask, however these appear to leak if the task never completes.
It is also not allowed to simply put evtTask in a using block as trying to dispose the incomplete task is not allowed.
var jobUuid = Guid.NewGuid();
var evtTask = Events.FirstAsync((x) => x.Action == Action.JobComplete && x.JobUuid == jobUuid).ToTask();
// e.g. if this throws without ever sending the message
await SendMessage($"job {jobUuid} download {url}");
var evt = await evtTask;
if (evt.Success)
{
...
}
Does the library provide a simple means for this use-case that will unsubscribe on leaving the scope?
var jobUuid = Guid.NewGuid();
using(var evtTask = Events.FirstAsync((x) => x.Action == Action.JobComplete && x.JobUuid == jobUuid)
.ToDisposableTask())) // Some method like this
{
// e.g. if this throws without ever sending the message
await SendMessage($"job {jobUuid} download {url}");
var evt = await evtTask;
if (evt.Success)
{
...
}
} // Get rid of the FirstAsync task if leave here before it completes for any reason
Disposing Task will not help, since it does nothing useful (in most situations, including this one). What will help though is cancelling task. Cancelling disposes underlying subscription created by ToTask and so, resolves this "leak".
So it can go like this:
Task<Event> evtTask;
using (var cts = new CancellationTokenSource()) {
evtTask = Events.FirstAsync((x) => x.Action == Action.JobComplete && x.JobUuid == jobUuid)
.ToTask(cts.Token);
// e.g. if this throws without ever sending the message
try {
await SendMessage($"job {jobUuid} download {url}");
}
catch {
cts.Cancel(); // disposes subscription
throw;
}
}
var evt = await evtTask;
if (evt.Success)
{
...
}
Of course you can wrap that in some more convenient form (like extension method). For example:
public static class ObservableExtensions {
public static CancellableTaskWrapper<T> ToCancellableTask<T>(this IObservable<T> source) {
return new CancellableTaskWrapper<T>(source);
}
public class CancellableTaskWrapper<T> : IDisposable
{
private readonly CancellationTokenSource _cts;
public CancellableTaskWrapper(IObservable<T> source)
{
_cts = new CancellationTokenSource();
Task = source.ToTask(_cts.Token);
}
public Task<T> Task { get; }
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
}
}
Then it becomes close to what you want:
var jobUuid = Guid.NewGuid();
using (var evtTask = Events.FirstAsync((x) => x.Action == Action.JobComplete && x.JobUuid == jobUuid).ToCancellableTask()) {
await SendMessage($"job {jobUuid} download {url}");
var evt = await evtTask.Task;
if (evt.Success) {
...
}
}
You can either use TPL Timeout (as referenced by #Fabjan), or the Rx/System.Reactive version of Timeout.
using sounds nice, but doesn't make sense. Using is the equivalent of calling .Dispose on something at the end of the using block. The problem here, I'm assuming, is that your code never gets past await evtTask. Throwing all of that in a hypothetical using wouldn't change anything: Your code is still waiting forever.
At a higher level, your code is more imperative than reactive, you may want to refactor it to something like this:
var subscription = Events
.Where(x => x.Action == Action.JobComplete)
.Subscribe(x =>
{
if(x.Success)
{
//...
}
else
{
//...
}
});

Do I create a deadlock for Task.WhenAll()

I seem to be experiencing a deadlock with the following code, but I do not understand why.
From a certain point in code I call this method.
public async Task<SearchResult> Search(SearchData searchData)
{
var tasks = new List<Task<FolderResult>>();
using (var serviceClient = new Service.ServiceClient())
{
foreach (var result in MethodThatCallsWebservice(serviceClient, config, searchData))
tasks.Add(result);
return await GetResult(tasks);
}
Where GetResult is as following:
private static async Task<SearchResult> GetResult(IEnumerable<Task<FolderResult>> tasks)
{
var result = new SearchResult();
await Task.WhenAll(tasks).ConfigureAwait(false);
foreach (var taskResult in tasks.Select(p => p.MyResult))
{
foreach (var folder in taskResult.Result)
{
// Do stuff to fill result
}
}
return result;
}
The line var result = new SearchResult(); never completes, though the GUI is responsive because of the following code:
public async void DisplaySearchResult(Task<SearchResult> searchResult)
{
var result = await searchResult;
FillResultView(result);
}
This method is called via an event handler that called the Search method.
_view.Search += (sender, args) => _view.DisplaySearchResult(_model.Search(args.Value));
The first line of DisplaySearchResult gets called, which follows the path down to the GetResult method with the Task.WhenAll(...) part.
Why isn't the Task.WhenAll(...) ever completed? Did I not understand the use of await correctly?
If I run the tasks synchronously, I do get the result but then the GUI freezes:
foreach (var task in tasks)
task.RunSynchronously();
I read various solutions, but most were in combination with Task.WaitAll() and therefore did not help much. I also tried to use the help from this blogpost as you can see in DisplaySearchResult but I failed to get it to work.
Update 1:
The method MethodThatCallsWebservice:
private IEnumerable<Task<FolderResult>> MethodThatCallsWebservice(ServiceClient serviceClient, SearchData searchData)
{
// Doing stuff here to determine keys
foreach(var key in keys)
yield return new Task<FolderResult>(() => new FolderResult(key, serviceClient.GetStuff(input))); // NOTE: This is not the async variant
}
Since you have an asynchronous version of GetStuff (GetStuffAsync) it's much better to use it instead of offloading the synchronous GetStuff to a ThreadPool thread with Task.Run. This wastes threads and limits scalability.
async methods return a "hot" task so you don't need to call Start:
IEnumerable<Task<FolderResult>> MethodThatCallsWebservice(ServiceClient serviceClient, SearchData searchData)
{
return keys.Select(async key =>
new FolderResult(key, await serviceClient.GetStuffAsync(input)));
}
You need to start your tasks before you return them. Or even better use Task.Run.
This:
yield return new Task<FolderResult>(() =>
new FolderResult(key, serviceClient.GetStuff(input)))
// NOTE: This is not the async variant
Is better written as:
yield return Task.Run<FolderResult>(() =>
new FolderResult(key, serviceClient.GetStuff(input)));

Await list of async predicates, but drop out on first false

Imagine the following class:
public class Checker
{
public async Task<bool> Check() { ... }
}
Now, imagine a list of instances of this class:
IEnumerable<Checker> checkers = ...
Now I want to control that every instance will return true:
checkers.All(c => c.Check());
Now, this won't compile, since Check() returns a Task<bool> not a bool.
So my question is: How can I best enumerate the list of checkers?
And how can I shortcut the enumeration as soon as a checker returns false?
(something I presume All( ) does already)
"Asynchronous sequences" can always cause some confusion. For example, it's not clear whether your desired semantics are:
Start all checks simultaneously, and evaluate them as they complete.
Start the checks one at a time, evaluating them in sequence order.
There's a third possibility (start all checks simultaneously, and evaluate them in sequence order), but that would be silly in this scenario.
I recommend using Rx for asynchronous sequences. It gives you a lot of options, and it a bit hard to learn, but it also forces you to think about exactly what you want.
The following code will start all checks simultaneously and evaluate them as they complete:
IObservable<bool> result = checkers.ToObservable()
.SelectMany(c => c.Check()).All(b => b);
It first converts the sequence of checkers to an observable, calls Check on them all, and checks whether they are all true. The first Check that completes with a false value will cause result to produce a false value.
In contrast, the following code will start the checks one at a time, evaluating them in sequence order:
IObservable<bool> result = checkers.Select(c => c.Check().ToObservable())
.Concat().All(b => b);
It first converts the sequence of checkers to a sequence of observables, and then concatenates those sequences (which starts them one at a time).
If you do not wish to use observables much and don't want to mess with subscriptions, you can await them directly. E.g., to call Check on all checkers and evaluate the results as they complete:
bool all = await checkers.ToObservable().SelectMany(c => c.Check()).All(b => b);
And how can I shortcut the enumeration as soon as a checker returns false?
This will check the tasks' result in order of completion. So if task #5 is the first to complete, and returns false, the method returns false immediately, regardless of the other tasks. Slower tasks (#1, #2, etc) would never be checked.
public static async Task<bool> AllAsync(this IEnumerable<Task<bool>> source)
{
var tasks = source.ToList();
while(tasks.Count != 0)
{
var finishedTask = await Task.WhenAny(tasks);
if(! finishedTask.Result)
return false;
tasks.Remove(finishedTask);
}
return true;
}
Usage:
bool result = await checkers.Select(c => c.Check())
.AllAsync();
All wasn't built with async in mind (like all LINQ), so you would need to implement that yourself:
async Task<bool> CheckAll()
{
foreach(var checker in checkers)
{
if (!await checker.Check())
{
return false;
}
}
return true;
}
You could make it more reusable with a generic extension method:
public static async Task<bool> AllAsync<TSource>(this IEnumerable<TSource> source, Func<TSource, Task<bool>> predicate)
{
foreach (var item in source)
{
if (!await predicate(item))
{
return false;
}
}
return true;
}
And use it like this:
var result = await checkers.AllAsync(c => c.Check());
You could do
checkers.All(c => c.Check().Result);
but that would run the tasks synchronously, which may be very slow depending on the implementation of Check().
Here's a fully functional test program, following in steps of dcastro:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AsyncCheckerTest
{
public class Checker
{
public int Seconds { get; private set; }
public Checker(int seconds)
{
Seconds = seconds;
}
public async Task<bool> CheckAsync()
{
await Task.Delay(Seconds * 1000);
return Seconds != 3;
}
}
class Program
{
static void Main(string[] args)
{
var task = RunAsync();
task.Wait();
Console.WriteLine("Overall result: " + task.Result);
Console.ReadLine();
}
public static async Task<bool> RunAsync()
{
var checkers = new List<Checker>();
checkers
.AddRange(Enumerable.Range(1, 5)
.Select(i => new Checker(i)));
return await checkers
.Select(c => c.CheckAsync())
.AllAsync();
}
}
public static class ExtensionMethods
{
public static async Task<bool> AllAsync(this IEnumerable<Task<bool>> source)
{
var tasks = source.ToList();
while (tasks.Count != 0)
{
Task<bool> finishedTask = await Task.WhenAny(tasks);
bool checkResult = finishedTask.Result;
if (!checkResult)
{
Console.WriteLine("Completed at " + DateTimeOffset.Now + "...false");
return false;
}
Console.WriteLine("Working... " + DateTimeOffset.Now);
tasks.Remove(finishedTask);
}
return true;
}
}
}
Here's sample output:
Working... 6/27/2014 1:47:35 AM -05:00
Working... 6/27/2014 1:47:36 AM -05:00
Completed at 6/27/2014 1:47:37 AM -05:00...false
Overall result: False
Note that entire eval ended when exit condition was reached, without waiting for the rest to finish.
As a more out-of-the-box alternative, this seems to run the tasks in parallel and return shortly after the first failure:
var allResult = checkers
.Select(c => Task.Factory.StartNew(() => c.Check().Result))
.AsParallel()
.All(t => t.Result);
I'm not too hot on TPL and PLINQ so feel free to tell me what's wrong with this.

Nested asynchronous tasks

I would like to know if it's possible to improve this code for better performance. I'm new to the whole async thing on the serverside, so please bear with me here:
con.GetGame(id, game => {
foreach(Player p in game.Team1)
{
p.SomeExtraDetails = GetPlayerDetails(p.Id);
}
// I would like the player data to be set on all players
// before ending up here
});
private PlayerDetails GetPlayerDetails(double playerId)
{
var task = con.GetPlayer(playerId);
PlayerDetails ret = null;
Task continuation = task.ContinueWith(t =>
{
ret = t.Result;
});
continuation.Wait();
return ret;
}
If I got it right, continuation.Wait(); blocks the main thread.
Is there any way to make the tasks run simultaneously?
Ideally, you'd make these operations asynchronous all the way down:
private Task<PlayerDetails> GetPlayerDetailsAsync(double playerId)
{
return con.GetPlayer(playerId);
}
con.GetGame(id, game => {
var tasks = game.Team1
.Select(p => new { Player=p, Details=GetPlayerDetailsAsync(p.Id)})
.ToList(); // Force all tasks to start...
foreach(var t in tasks)
{
t.Player.SomeExtraDetails = await t.Details;
}
// all player data is now set on all players
});
If that isn't an option (ie: you're not using VS 2012), you could simplify your code to:
// This is a more efficient version of your existing code
private PlayerDetails GetPlayerDetails(double playerId)
{
var task = con.GetPlayer(playerId);
return task.Result;
}
con.GetGame(id, game => {
// This will run all at once, but block until they're done
Parallel.ForEach(game.Team1, p =>
{
p.SomeExtraDetails = GetPlayerDetails(p.Id);
});
});
consider using Parallel.ForEach in your GetGame page instead of Task.ContinueWith
Alternative solution without LINQ (although I like Reed Copsey's solution). However, beware that, as pointed out in the comments, this solution introduces an overhead by encapsulating the call to GetPlayerDetailsAsync() inside Tasks created by Task.Run().
Requires .NET 4.5 and C# 5.
con.GetGame(id, game => {
var tasks = new List<Task>();
foreach(Player p in game.Team1)
{
tasks.Add(Task.Run(async () => p.SomeExtraDetails = await GetPlayerDetailsAsync(p.Id)));
}
Task.WaitAll(tasks.ToArray());
});
private Task<PlayerDetails> GetPlayerDetailsAsync(double playerId)
{
return con.GetPlayerAsync(playerId);
});
Further, in order to catch up on the Task-based Asynchronous Pattern (TAP) with .NET 4.5 I highly recommend reading: Task-based Asynchronous Pattern - by Stephen Toub, Microsoft.

Categories

Resources