If the Task exposed by my TaskCompletionSource may never get called how can I deffer computation of the Result unless and until someone awaits the task?
For example, I want to block other async threads of execution until a ManualResetEvent is signaled using the following function WaitOneAsync. I complete the TaskCompleationSource in the callback of ThreadPool.RegisterWaitForSingleObject which happens when the WaitHandle is signaled. But if no one awaits the task then I don't want to RegisterWaitForSingleObject (nor do I want to RegisterWaitForSingleObject if the task is awaited after the WaitHandle is signaled).
How can I change WaitOneAsync so that the work to compute the result, to RegisterWaitForSingleObject, only happens after someone awaits the TaskCompleationSource.Task?
I believe the answer may lie in a custom TaskAwaiter as described here Implement AsyncManualResetEvent using Lazy<T> to determine if the task has been awaited by Scott Chamberlain but I can't quite get from his example to my solution... :(
public static async Task<T> WaitOneAsync<T>(this WaitHandle waitHandle, Func<T> result) {
var tcs = new TaskCompletionSource<T>();
RegisteredWaitHandle rwh = null;
rwh = ThreadPool.RegisterWaitForSingleObject(
waitObject: waitHandle,
callBack: (s, t) => {
rwh.Unregister(null);
tcs.TrySetResult(result());
},
state: null,
millisecondsTimeOutInterval: -1,
executeOnlyOnce: true
);
return await tcs.Task;
}
As usr said, it's not possible to do something in reaction to a Task being awaited. But if you're okay with using a custom awaitable, then you can.
An easy way to do that is to use AsyncLazy from Stephen Cleary's AsyncEx:
private static Task<T> WaitOneAsyncImpl<T>(WaitHandle waitHandle, Func<T> result)
{
if (waitHandle.WaitOne(0))
return Task.FromResult(result());
var tcs = new TaskCompletionSource<T>();
RegisteredWaitHandle rwh = null;
rwh = ThreadPool.RegisterWaitForSingleObject(
waitObject: waitHandle,
callBack: (s, t) =>
{
rwh.Unregister(null);
tcs.TrySetResult(result());
},
state: null,
millisecondsTimeOutInterval: -1,
executeOnlyOnce: true
);
return tcs.Task;
}
public static AsyncLazy<T> WaitOneAsync<T>(this WaitHandle waitHandle, Func<T> result)
=> new AsyncLazy<T>(() => WaitOneAsyncImpl(waitHandle, result));
This is not possible exactly as you described your requirements. The TPL does not provide an event or a callback when someone adds a continuation or waits on a task.
So you need to structure the API so that only tasks that are needed are actually produced. What about this?
public static Func<Task<T>> CreateWaitOneAsyncFactory<T>(this WaitHandle waitHandle, Func<T> result) {
return () => WaitOneAsync(waitHandle, result);
}
This returns a task factory instead of a task. This is cheating but the only possible solutions involve cheating of this kind.
You can return a custom awaitable as well. But that would not involve tasks at all and it misses the composability features of tasks. Awaitables mostly are a C# concept. Exposing them can result in unclean APIs.
Unrelated to your question: You can remove the await tcs.Task and return that task directly. Also, the result function is not needed. Return a Task that has no result. Callers can then add a result if they wish. This makes the API of WaitOneAsync cleaner.
Related
I've done this Unit Test and I don't understand why the "await Task.Delay()" doesn't wait !
[TestMethod]
public async Task SimpleTest()
{
bool isOK = false;
Task myTask = new Task(async () =>
{
Console.WriteLine("Task.BeforeDelay");
await Task.Delay(1000);
Console.WriteLine("Task.AfterDelay");
isOK = true;
Console.WriteLine("Task.Ended");
});
Console.WriteLine("Main.BeforeStart");
myTask.Start();
Console.WriteLine("Main.AfterStart");
await myTask;
Console.WriteLine("Main.AfterAwait");
Assert.IsTrue(isOK, "OK");
}
Here is the Unit Test output :
How is this possible an "await" doesn't wait, and the main thread continues ?
new Task(async () =>
A task does not take a Func<Task>, but an Action. It will call your asynchronous method and expect it to end when it returns. But it does not. It returns a task. That task is not awaited by the new task. For the new task, the job is done once the method returned.
You need to use the task that already exists instead of wrapping it in a new task:
[TestMethod]
public async Task SimpleTest()
{
bool isOK = false;
Func<Task> asyncMethod = async () =>
{
Console.WriteLine("Task.BeforeDelay");
await Task.Delay(1000);
Console.WriteLine("Task.AfterDelay");
isOK = true;
Console.WriteLine("Task.Ended");
};
Console.WriteLine("Main.BeforeStart");
Task myTask = asyncMethod();
Console.WriteLine("Main.AfterStart");
await myTask;
Console.WriteLine("Main.AfterAwait");
Assert.IsTrue(isOK, "OK");
}
The problem is that you are using the non-generic Task class, that is not meant to produce a result. So when you create the Task instance passing an async delegate:
Task myTask = new Task(async () =>
...the delegate is treated as async void. An async void is not a Task, it cannot be awaited, its exception cannot be handled, and it's a source of thousands of questions made by frustrated programmers here in StackOverflow and elsewhere. The solution is to use the generic Task<TResult> class, because you want to return a result, and the result is another Task. So you have to create a Task<Task>:
Task<Task> myTask = new Task<Task>(async () =>
Now when you Start the outer Task<Task> it will be completed almost instantly because its job is just to create the inner Task. You'll then have to await the inner Task as well. This is how it can be done:
myTask.Start(TaskScheduler.Default);
Task myInnerTask = await myTask;
await myInnerTask;
You have two alternatives. If you don't need an explicit reference to the inner Task then you can just await the outer Task<Task> twice:
await await myTask;
...or you can use the built-in extension method Unwrap that combines the outer and the inner tasks into one:
await myTask.Unwrap();
This unwrapping happens automatically when you use the much more popular Task.Run method that creates hot tasks, so the Unwrap is not used very often nowadays.
In case you decide that your async delegate must return a result, for example a string, then you should declare the myTask variable to be of type Task<Task<string>>.
Note: I don't endorse the use of Task constructors for creating cold tasks. As a practice is generally frowned upon, for reasons I don't really know, but probably because it is used so rarely that it has the potential of catching other unaware users/maintainers/reviewers of the code by surprise.
General advice: Be careful everytime you are supplying an async delegate as an argument to a method. This method should ideally expect a Func<Task> argument (meaning that understands async delegates), or at least a Func<T> argument (meaning that at least the generated Task will not be ignored). In the unfortunate case that this method accepts an Action, your delegate is going to be treated as async void. This is rarely what you want, if ever.
[Fact]
public async Task SimpleTest()
{
bool isOK = false;
Task myTask = new Task(() =>
{
Console.WriteLine("Task.BeforeDelay");
Task.Delay(3000).Wait();
Console.WriteLine("Task.AfterDelay");
isOK = true;
Console.WriteLine("Task.Ended");
});
Console.WriteLine("Main.BeforeStart");
myTask.Start();
Console.WriteLine("Main.AfterStart");
await myTask;
Console.WriteLine("Main.AfterAwait");
Assert.True(isOK, "OK");
}
I have an awaitable object which is NOT a Task (for example, an IObservable<T> with RX installed). I want to create a Task, which will end up as cancelled if the supplied CancellationToken is cancelled or return the result of the awaitable object otherwise. I came up with the following code:
public static Task ObserveTokenAsync(CancellationToken token)
{
TaskCompletionSource<Unit> tcs = new TaskCompletionSource<Unit>();
token.Register(() => tcs.SetCanceled());
return tcs.Task;
}
public static async Task<T> WrapObservableAsync<T>(IObservable<T> obs)
{
return await obs;
}
public static async Task<T> AwaitWhileObservingTokenAsync<T>(IObservable<T> obs, CancellationToken token)
{
var obsTask = WrapObservableAsync(obs);
var tokenTask = ObserveTokenAsync(token);
await Task.WhenAny(obsTask, tokenTask).ConfigureAwait(false);
token.ThrowIfCancellationRequested();
return obsTask.Result;
}
With this approach I will need to overload/rewrite the last two methods for each of the awaitable types I will be using. Is there any better way to do this? My guess is that the INotifyCompletion interface may somehow be useful.
Also, can the ObserveTokenAsync method cause some kind of resource/memory leaks if the supplied tokens won't get cancelled? If yes, will setting the TaskCompletionSource as finished at the end of the AwaitWhileObservingTokenAsync method will be a good way to fix it?
Use the TaskObservableExtensions.ToTask extension method from Rx. It takes a CancellationToken and will take the last element from the observable when available to finish the returned task. When the CancellationToken is canceled the returned task will throw an OperationCanceledException when awaited. If the observable does not contain any elements, the returned task will throw an exception when awaited (probably an InvalidOperationException though I would have to look that up).
Is there a way to use the Task-based Asynchronous Pattern (TAP) in .NET 4.0 without the await and async keywords? (I ask because we are stuck in C# 4.0.)
Also, is there an example of using TAP with WCF with .NET 4.0?
Yes you can. The TAP is just a sensible formalization of best practice when working with asynchronous code. Basically a TAP method
Returns a 'hot' (running) Task or Task<TResult>.
Has an 'Async' suffix (e.g. SomeMethodAsync(...)).
Is overloaded to accept a cancellation token.
Returns quickly to the caller (with small initialisation phase).
Does not tie up a thread if I/O bound.
So, an example might be
private Task SomeMethodAsync(CancellationToken token)
{
return Task.Factory.StartNew(() =>
{
// Do something...
}, token);
}
use the method and attach continuation which uses the UI synchronization context.
private void SomeOtherMethod()
{
var tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext()
// Options 1.
Task t = SomeMethodAsync(token);
Task c = t.ContinueWith(ant =>
{
/* Do something and check exceptions */
}, CancellationToken.None,
TaskContinuationOptions.None,
scheduler);
// Options 2.
SomeMethodAsync(token).ContinueWith(ant =>
{
/* Do something and check exceptions */
}, CancellationToken.None,
TaskContinuationOptions.None,
scheduler);
}
Or do it all in one go
Task t = Task.Factory.StartNew(() =>
{
/* Do Something */
}, token).ContinueWith(ant =>
{
/* Do something on UI thread after task has completed and check exceptions */
}, CancellationToken.None,
TaskContinuationOptions.None,
scheduler);
You can also implement the TAP pattern manually for better control over implementation. To implement the TAP yourself, you create a TaskCompletionSource<TResult> object, perform the asynchronous operation, and when it completes, call the SetResult, SetException, or SetCanceled method, or the Try version of one of these methods. When you implement a TAP method manually, you must complete the resulting task when the represented asynchronous operation completes. For example:
public static Task<int> ReadTask(this Stream stream,
byte[] buffer, int offset, int count, object state)
{
var tcs = new TaskCompletionSource<int>();
stream.BeginRead(buffer, offset, count, ar =>
{
try { tcs.SetResult(stream.EndRead(ar)); }
catch (Exception exc) { tcs.SetException(exc); }
}, state);
return tcs.Task;
}
Consume the TaskCompleationSource from the consumer.
I hope this helps.
You don't need async/await. The keywords can be
ContinueWith and TaskScheduler.FromCurrentSynchronizationContext
Task.Factory.StartNew(() => { return "test"; } )
.ContinueWith(task => { this.textBox1.Text = task.Result; },
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
This is roughly equal to
var str = await SomeFuncAsync() //returning "test";
this.textBox1.Text = str;
Is there a way to use Task-based Asynchronous Pattern (TAP) in .NET
4.0 without the keyword await or async? I ask because we are stuck in C#4)
One notable and handy hack is to use yield and IEnumerable<Task>. E.g., from Stephen Toub's "Processing Sequences of Asynchronous Operations with Tasks":
IEnumerable<Task> DoExample(string input)
{
var aResult = DoAAsync(input);
yield return aResult;
var bResult = DoBAsync(aResult.Result);
yield return bResult;
var cResult = DoCAsync(bResult.Result);
yield return cResult;
…
}
…
Task t = Iterate(DoExample(“42”));
This way, you can have a pseudo-synchronous linear code flow similar to async/await.
Without the async/await keywords you won't be able to utilize the easiness provided by compiler to use the new pattern. However you can leverage Task based parallelism using Task Parallel Library (TPL) in .NET 4 framework
yeah there is. Async Wrappers for "Begin/End" methods comes to my mind;
public static Task<WebResponse> GetResponseAsync(this WebRequest client)
{
return Task<WebResponse>.Factory.FromAsync(client.BeginGetResponse,
client.EndGetResponse, null);
}
i guess what you are looking for Implement a WCF Asynchronous Service Operation with Task
I'm trying to create an async ProducerConsumerCollection and for that, I'm using this msdn page (http://msdn.microsoft.com/en-us/library/hh873173.aspx (bottom of the page)).
I'm now trying to add a timeout, here is what I do :
public async Task<T> TakeWithTimeout(int timeout)
{
Task<T> takeTask = this.Take();
if (timeout <= 0 || takeTask == await Task.WhenAny(this.tasks.Take(), Task.Delay(timeout)))
{
return await takeTask;
}
else
{
// Timeout
return default(T);
}
}
}
The problem with this code is that, in case of timeout, it does not cancel the task created by the Take() method.
Since this task has been "created" by the TaskCompletionSource, I cannot give it a cancellationToken?
So, how to proceed to cancel it and properly implement this Take with timeout ?
Thanks :)
Writing a cancel-safe async-friendly producer/consumer collection is non-trivial. What you need to do is change Take to accept a CancellationToken as a parameter, and it should register a handler so that when it is cancelled the TaskCompletionSource is cancelled.
I highly recommend you use BufferBlock<T>, which has cancellation support built-in.
If you can't use TPL Dataflow (e.g., you're working in a PCL or have target platforms unsupported by Dataflow), then you can use the producer/consumer collections in my open-source AsyncEx library (such as AsyncProducerConsumerQueue or AsyncCollection). These are both based on AsyncLock and AsyncConditionVariable, a design I describe briefly on my blog (which does not get into the cancellation details). The key behind supporting cancellation in a producer/consumer collection with this design is to support cancellation in AsyncConditionVariable.WaitAsync; once your condition variable type supports cancellation, then your collection will easily support it, too.
I'm just going to post my solution to the question How to cancel a task from a TaskCompletionSource because that is what I needed myself.
I'm guessing this could be used for your specific need, but it's not tied to a specific timeout functionality, so this is a general solution (or so I hope).
This is an extension method:
public static async Task WaitAsync<T>(this TaskCompletionSource<T> tcs, CancellationToken ctok)
{
CancellationTokenSource cts = null;
CancellationTokenSource linkedCts = null;
try {
cts = new CancellationTokenSource();
linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, ctok);
var exitTok = linkedCts.Token;
Func<Task> listenForCancelTaskFnc = async () => {
await Task.Delay(-1, exitTok).ConfigureAwait(false);
};
var cancelTask = listenForCancelTaskFnc();
await Task.WhenAny(new Task[] { tcs.Task, cancelTask }).ConfigureAwait(false);
cts.Cancel();
} finally {
if(linkedCts != null) linkedCts.Dispose();
}
}
Usage:
async Task TestAsync(CancellationToken ctok) {
var tcs = new TaskCompletionSource<bool>();
if (somethingOrTheOther) {
tcs.TrySetResult(true);
}
await tcs.WaitAsync(ctok);
}
The idea is to have a supervisory async Task waiting essentially forever until it is cancelled, which we can use to 'exit early' in case the TaskCompletionSource is not yet satisfied, but we need to exit anyhow due to a cancel request.
The supervisory Task is guaranteed to be cancelled at the end of WaitAsync regardless how it falls out of the WhenAny. Either the TaskCompletionSource is satisfied with a result, and WhenAny completes, briefly leaving the supervisory sleeper task in tact until the next line where cts.Cancel() is called, or it was cancelled with the exitToken, which is a combined token of the passed in ctok or the internal one cts.Token.
Anyhow, I hope this makes sense -- please let me know if this code has any problems...
I'd like to use Task return from a method to return a the value when it becomes available at later time, so that the caller can either block using Wait or attach a continuation or even await it. The best I can think of is this:
public class Future<T> {
private ManualResetEvent mre = new ManualResetEvent();
private T value;
public async Task<T> GetTask() {
mre.WaitOne();
return value;
}
public void Return(T value) {
this.value = value;
mre.Set();
}
}
Main problem with that is that mre.WaitOne() is blocking, so i assume that every call to GetTask() will schedule a new thread to block. Is there a way to await a WaitHandle in an async manner or is there already a helper for building the equivalent functionality?
Edit: Ok, is TaskCompletionSource what i'm looking for and i'm just making life hard on myself?
Well, I guess I should have dug around a bit more before posting. TaskCompletionSource is exactly what I was looking for
var tcs = new TaskCompletionSource<int>();
bool completed = false;
var tc = tcs.Task.ContinueWith(t => completed = t.IsCompleted);
tcs.SetResult(1);
tc.Wait();
Assert.IsTrue(completed);
Blocking a thread is bad by calling the WaitHandle.WaitOne(), but that's how events work, and the selected answer does not make a lot of sense, because it does not do anything asynchronously.
HOWEVER, the .NET framework can utilize worker threads from a thread pool to wait on multiple events at the same time (see ThreadPool.RegisterWaitForSingleObject) - this will improve overall resource utilization in your app if you need to wait on multiple WaitHandles at the same time.
So what you can do, is to register the WaitHandle for waiting on a worker thread, and set the callback with desired continuation.
With the AsyncWaitHandle extension library (NuGet) this can be done in one line:
var mre = new ManualResetEvent();
T myValue = ...;
Task<T> futureValueTask = mre.WaitOneAsync().ContinueWith(() => myValue);
Overall, my humble suggestion is to review the code and do this instead:
async Task MyCode()
{
var mre = new ManualResetEvent();
StartDoingSmthAsynchronouslyThatPulsesTheEvent(mre);
await mre;
// finish routine here when the event fires
}
Can't you just leverage TaskEx.WhenAll(t1, t2, t3...) to do the waiting. You'd need a real task that represents the doing of the work, but if you said something like:
private Task<T> myRealWork;
private T value;
// ...
public async Task<T> GetTask()
{
value = await TaskEx.WhenAll(myRealWork);
return value;
}
Although you can probably just await the myRealWork task as well. I don't see in your code where the value is actually being computed. That might require something like:
public async Task<T> GetTask()
{
value = await TaskEx.RunEx(() => ComputeRealValueAndReturnIt());
return value;
}