Given an asynchronous method that does both CPU and IO work such as:
Public Async Function RunAsync() As Task
DoWork()
Await networkStream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(False)
End Function
Which of the following options is the best way to call that asynchronous method from Task.Run in Visual Basic and why?
Which is the VB equivalent for C# Task.Run(() => RunAsync())?
Await Task.Run(Function() RunAsync())
' or
Await Task.Run(Sub() RunAsync())
Are the Async/Await keywords within Task.Run necessary or redundant? This comment claims they're redundant, but this answer suggests it might be necessary in certain cases:
Await Task.Run(Async Function()
Await RunAsync()
End Function)
Is ConfigureAwait useful within Task.Run?
Await Task.Run(Function() RunAsync().ConfigureAwait(False))
Await Task.Run(Async Function()
Await RunAsync().ConfigureAwait(False)
End Function)
Which of the above 5 Task.Run options is best practice?
Note: There's a similar question How to call Async Method within Task.Run? but it's for C#, the selected answer has negative votes, and doesn't address ConfigureAwait.
Which is the VB equivalent for C# Task.Run(() => RunAsync())?
My VB is horribly rusty, but it should not be the Sub one, so I'd go with:
Task.Run(Function() RunAsync())
Are the Async/Await keywords within Task.Run necessary or redundant?
I have a blog post on the subject. In this case, they're redundant because the delegate is trivial.
Is ConfigureAwait useful within Task.Run?
Only if you do an Await.
Related
Take this async function:
Public Async Function MyAsyncFunction() As Task(Of String)
Return Await SomeFunctionThatReturnsAString()
End Function
If I call it from a synchronous function like this:
Public Function MySyncFunction() As String
Return MyAsyncFunction.Result
End Function
... the function hangs.
I wondered if it is possible to write an extension like this (the extension below does not work):
Public Module TaskExtensions
<Extension()>
Public Function SyncronousResult(Of T)(aTask As Task(Of T)) As T
Dim result As T = Nothing
Task.Run(Sub()
result = aTask.Result
End Sub).Wait()
Return result
End Function
End Module
... so I could call it like this:
Public Function MySyncFunction() As String
Return MyAsyncFunction.SyncronousResult
End Function
?
The ideal solution is not to block on asynchronous code (as I explain on my blog).
But, if you're in a situation where you literally can't use Await (for some reason), then you can try using one of the techniques in my Brownfield Async article. Note that there is no general-purpose solution that works everywhere.
The one you suggest is blocking for the result in a thread pool thread, which may or may not work. In the example code you posted, it wouldn't work because MyAsyncFunction has already captured the UI context and will attempt to resume in that context.
What you can try is call MyAsyncFunction from inside a delegate passed to Task.Run and then call GetAwaiter().GetResult() on the returned task. That works in most cases. In my article I refer to this as the "Thread Pool Hack".
In order to use some online service, I need to call an API three times.
Upload the file
Request an operation
Download the file
I can handle all operations individually but I have hard times to sequence them as they are asynchronous. I wish I can handle all operations in one function call and all I am asking here is some advice to start on the right foot.
I have been playing with promises but got lost in the progress.
function main(){
//Pseudo code
calling async step1
exit if step1 failed
calling async step2
exit if step2 failed
calling async ste3
exit if step3 failed
return OK
}
Thanks in advance.
Since you've given us no real code and no specific information on your APIs, I will offer an answer assuming that the APIs return promises or can be made to return promises. In that case, sequencing and doing error handling is quite simple:
ascync function main() {
let step1Result = await step1();
let step2Result = await step2();
let step3Result = await step3();
return finalValue;
}
// usage
main().then(finalResult => {
console.log(finalResult);
}).catch(err => {
console.log(err);
});
Some things to know:
Because main is declared async, it can use await internal to its implementation.
Because main is delcared async, it will always return a promise
This code assumes that step1(), step2() and step3() return promises that are linked to the completion or error of one or more asynchronous operations.
When the function is executing, as soon as it hits the first await, the function will return an unresolved promise back to the caller.
If any of the await stepX() calls reject (e.g. have an error), that will abort further execution of the function and reject the promise that was previously returned with that specific error. It works analogous to throw err in synchronous programming, but the throw is caught automatically by the async function and turned into a reject for the promise that it already returned.
Your final return value in the function is not actually what is returned because remember, a promise was already returned from the function when it hit the first await. Instead, the value you return becomes the resolved value of that promise that was already returned.
If your API interfaces don't currently return promises, then you can usually find a wrapper that someone has done to create a version that will return promises (since promises are the modern way of working with asynchronous interfaces in Javascript). Or, you can create your own wrapper. In node.js, you can use util.promisify() or you can manually make your own wrapper (just takes a few lines of code).
If you need to catch an error within the function in order to handle it and continue, you can either wrap a given await call in try/catch or use .catch() on the promise and "handle" the error and continue processing, again similar to handling exceptions in synchronous code.
If any of the steps had an error and rejected their promise, then main() will abort and reject similar to throwing an exception in synchronous code.
See also:
How to chain and share prior results with Promises
I would like to to use the Response.OnStarting to execute some code which leverages the async await pattern. The Response.OnStarting method is defined as
public void OnStarting(Func<Task> callback)
And I often see it used to modify headers via code like the following:
context.Response.OnStarting( () => {
//modify the headers or do some synchronous work
});
However I need to do some async work from the OnStarting delegate. Let's say the method performing the async work is declared as follows:
public Task DoWorkAsync() {
//write to a db or do something else async
return Task.CompletedTask;
}
Is it valid to call this method from via an OnStarting delegate using the following approach?
context.Response.OnStarting(async () => {
await DoWorkAsync();
});
In Visual Studio this compiles without warnings and it appears to work. However it seems odd to me that the Response.OnStarting method could be used to make both synchronous and async calls. Sometimes the async await world still gets me scratching my head a bit. Can you throw light on whether this approach works and why? And why it is that Response.OnStarting can be used with a sync and async anonymous method (if in fact it can)?
Update
I did some digging to see if I could find the code that gets calls the delegate passed to the OnStarting method.
What I found was that the DefaultHttpRespose object contains the OnStarting method and inside that method it basically calls the IHttpResponseFeature.OnStarting, see here:
public override void OnStarting(Func<object, Task> callback, object state)
{
if (callback == null)
{
throw new ArgumentNullException(nameof(callback));
}
HttpResponseFeature.OnStarting(callback, state);
}
link to source code
But interestingly, the only place I can find an implementation of IHttpResponseFeature.OnStarting is here with this code:
void IHttpResponseFeature.OnStarting(Func<object, Task> callback, object state)
{
var register = Prop<Action<Action<object>, object>>(OwinConstants.CommonKeys.OnSendingHeaders);
if (register == null)
{
throw new NotSupportedException(OwinConstants.CommonKeys.OnSendingHeaders);
}
// Need to block on the callback since we can't change the OWIN signature to be async
register(s => callback(s).GetAwaiter().GetResult(), state);
}
But that implementation blocks on the async delegate call. There is even a comment to that effect but I don't understand why that was necessary? And I'm not sure this is the implementation of IHttpResponseFeature.OnStarting that is getting ran, it's just the only one I could find on github. Any help greatly appreciated.
However it seems odd to me that the Response.OnStarting method could be used to make both synchronous and async calls.
Synchronous APIs must be implemented synchronously. A Func<int> must return an int; it cannot return a Task<int> instead.
Asynchronous APIs may be implemented asynchronously or synchronously. A Func<Task<int>> may have an asynchronous implementation, returning a Task<int> that will complete in the future. Or it may have a synchronous implementation, returning a Task<int> that is already completed with an int value.
When dealing with asynchronous APIs (including interfaces and delegate signatures), synchronous implementations are entirely permissible.
I wouldn't be distracted by the blocking implementation. The comment indicates that OWIN has a synchronous API in a place where there should be an asynchronous API, and IHttpResponseFeature.OnStarting is just hiding that oddity from you.
I have got this function which freezes the UI:
Public Sub ValidateUrlContentAsync(externalApplyURL As String)
AsyncManager.OutstandingOperations.Increment()
Dim result = Threading.Tasks.Task.
Run( _
Async Function()
Return Await ValidateLinks.ValidateUrlContentAsync(externalApplyURL)
End Function).
ContinueWith(
Sub(t)
Try
If t.IsFaulted Then
Throw t.Exception
End If
If t.Result.Error IsNot Nothing Then
ErrorHandler.Log.Warn(
String.Format("ValidationError: {0}, Exception: {1}", externalApplyURL, t.Result.Error))
End If
AsyncManager.Parameters("validationResult") = t.Result.ResultValue.ToString()
Finally
AsyncManager.OutstandingOperations.Decrement()
End Try
End Sub)
End Sub
Public Function ValidateUrlContentCompleted(validationResult As String) As ActionResult
Return Json(validationResult, JsonRequestBehavior.AllowGet)
End Function
I thought that task.run solves this issue because it creates a new thread separated from the UI thread, What's wrong with this code?
One thing that stands out to me is the use of three separate asynchronous code patterns (Await, ContinueWith, and AsyncManager) instead of just using Await.
The other major thing is that you're returning an ActionResult - indicating this is an ASP.NET application - and yet talking about a "UI thread". There is no UI thread on ASP.NET.
Thus, I reinterpret "freezes the UI" as "does not return a result until the handler is complete", which is exactly how ASP.NET is supposed to work.
So, first, remove all the unnecessary AsyncManager, ContinueWith, and Task.Run code, which really simplifies the method:
Public Function ValidateUrlContent(externalApplyURL As String) As Task(Of ActionResult)
Dim result = Await ValidateLinks.ValidateUrlContentAsync(externalApplyURL)
If result.Error IsNot Nothing Then
ErrorHandler.Log.Warn(String.Format("ValidationError: {0}, Exception: {1}", externalApplyURL, result.Error))
End If
Return Json(result.ResultValue.ToString(), JsonRequestBehavior.AllowGet)
End Function
Next, solve the "freezing the UI" problem. The proper place to solve this problem is in the UI, not on the server (ASP.NET) side. The way to prevent the UI from freezing is to call the server in an asynchronous way. If you UI is a .NET application, you can use Await with HttpClient to call it asynchronously.
You must Await the call to ValidateUrlContentAsnc. Turn it into a Function and return Task.
Is it possible to use Async CTP to emulate continuations and tail recursion?
I'm thinking something along the lines of:
async Task Loop(int count)
{
if (count == 0)
retrun;
await ClearCallStack();
//is it possible to continue here with a clean call stack?
Loop(count -1)
}
I guess one needs a custom scheduler and such, but would it be possible?
(that is, can it be used to recurse w/o blowing the call stack)
Yes, this is entirely possible.
In the newest Async CTP (Refresh for VS2010 SP1), there's a "GeneralThreadAffineContext" class in the Unit Testing sample (either in VB or C#). That provides the requisite helper code for just running an async method in a general purpose thread-affine manner.
By thread affinity, we mean that the async continuations get processed on the same context as the original thread, similarly to the behavior for WinForms/WPF, but without spinning up the real WPF or WinForms message loop.
Task.Yield()'s design is to defer the rest of the current method to the SynchronizationContext, so you don't even need to write your own await ClearCallStack(). Instead, your sample will boil down to:
async Task DoLoop(int count)
{
// yield first if you want to ensure your entire body is in a continuation
// Final method will be off of Task, but you need to use TaskEx for the CTP
await TaskEx.Yield();
if (count == 0)
return;
//is it possible to continue here with a clean call stack?
DoLoop(count -1)
}
void Loop(int count)
{
// This is a stub helper to make DoLoop appear synchronous. Even though
// DoLoop is expressed recursively, no two frames of DoLoop will execute
// their bodies simultaneously
GeneralThreadAffineContext.Run(async () => { return DoLoop(count); });
}