ASP.NET Core, overkilling Task.Run()? - asynchronous

Lets say we have an ASP.NET Core receiving a string as a payload, size order of couple of megabytes. First method implementation:
[HttpPost("updateinfos")]
public async Task UpdateInfos()
{
var len = (int)this.Request.ContentLength;
byte[] b = new byte[len];
await this.Request.Body.ReadAsync(b,0,len);
var content = Encoding.UTF8.GetString(b);
.....
}
Body is read with ReadAsync, this is good since we have I/O stuff on socket and having it asynchronous is for free due to the nature of the call itself. But if we have a look after, the GetString() method, is purely CPU, is blocking with linear complexity. Anyway this affect somehow the performance since other clients wait for my bytes to get converted in string. I think to avoid this the solution is to run GetString() on the thread pool, by this:
[HttpPost("updateinfos")]
public async Task UpdateInfos()
{
var len = (int)this.Request.ContentLength;
byte[] b = new byte[len];
await this.Request.Body.ReadAsync(b,0,len);
var content = await Task.Run(()=>ASCIIEncoding.UTF8.GetString(b));
.....
}
please don't mind the return right now, something more has to be done in the function.
So the question, is the second approach overkilling? If so, what is the boundary to discriminate what could be run as blocking and what has to be moved to another thread?

You are very much abusing Task.Run there. Task.Run is used to off-load work onto a different thread and asynchronously wait for it to complete. So every Task.Run call will cause thread context switches. Of course, that is usually a very bad idea to do for things that should not run on their own thread.
Things like ASCIIEncoding.UTF8.GetString(b) are really fast. The overhead involved in creating and managing a thread that encapsulates this is much larger than just executing this directly on the same thread.
You should generally use Task.Run only to off-load (primarily synchronous) work that can benefit from running on its own thread. Or in cases, where you have work that would take a bit longer but block the current execution.
In your example, that is simply not the case, so you should just call those methods synchronously.
If you really want to reduce the work for that code, you should look at how to work properly streams. What you do in your code is read the request body stream completely and only then you work on it (trying to translate into a string).
Instead of separating the process of reading the binary stream and then translating it into a string, you could just read the stream as a string directly using a StreamReader. That way, you can read the request body directly, even asynchronously. So depending on what you actually do with it afterwards, that may be a lot more efficient.

Related

How to call a async method from synchronous method?

I'm trying to call an asynchronous method from a synchronous method like below:
1. public List<Words> Get(string code)
{
Task<List<Words>> taskWords = GetWordsAsync(code);
var result = taskWords.Result;
return result;
}
private async Task<List<Words>> GetWordsAsync(string code)
{
var result = await codeService.GetWordsByCodeAsync(code);
return result;
}
But this lead to a deadlock, await is not getting the results from the method - GetWordsByCodeAsync
I've done a bit of research and came to know that if we are calling an async method from synchronous method we should use Task.Run
When I changed the code like below, it worked:
2. public List<Words> Get(string code)
{
Task<List<Words>> taskWords = Task.Run<List<Words>>(async () => await GetWordsAsync(code);
var result = taskWords.Result;
return result;
}
private async Task<List<Words>> GetWordsAsync(string code)
{
var result = await codeService.GetWordsByCodeAsync(code);
return result;
}
But I didn't get the context, why it caused a deadlock for 1st way and 2nd one worked fine.
I'd like to know:
What's the difference between two ways?
Is second one the correct way to call async method from synchronous method?
Will using the second method also causes a deadlock at some point of time if the result is large? or is it fail proof(safe) method to use?
Also, please suggest any best practices to better do it as I have to do 5 async calls from a synchronous method - just like taskWords, I have taskSentences etc.,
Note: I don't want to change everything to async. I want to call async method from synchronous method.
I don't want to change everything to async. I want to call async method from synchronous method.
From a technical standpoint, this doesn't make sense. Asynchronous means it doesn't block the calling thread; synchronous means it does. So you understand that if you block on asynchronous code, then it's no longer truly asynchronous? The only benefit to asynchronous code is that it doesn't block the calling thread, so if you block on the asynchronous code, you're removing all the benefit of asynchrony in the first place.
The only good answer is to go async all the way. There are some rare scenarios where that's not possible, though.
What's the difference between two ways?
The first one executes the asynchronous code directly and then blocks the calling thread, waiting for it to finish. You're running into a deadlock because the asynchronous code is attempting to resume on the calling context (which await does by default), and presumably you're running this code on a UI thread or in an ASP.NET Classic request context, which only allow one thread in the context at a time. There's already a thread in the context (the one blocking, waiting for the task to finish), so the async method cannot resume and actually finish.
The second one executes the asynchronous code on a thread pool thread and then blocks the calling thread, waiting for it to finish. There is no deadlock here because the asynchronous code resumes on its calling context, which is a thread pool context, so it just continues executing on any available thread pool thread.
Is second one the correct way to call async method from synchronous method?
There is no "correct" way to do this. There are a variety of hacks, each of which has different drawbacks, and none of which work in every situation.
Will using the second method also causes a deadlock at some point of time if the result is large? or is it fail proof(safe) method to use?
It will not deadlock. What it does, though, is execute GetWordsAsync on a thread pool thread. As long as GetWordsAsync can be run on a thread pool thread, then it will work.
Also, please suggest any best practices to better do it
I have written an article on the subject. In your case, if GetWordsAsync is safe to call on a thread pool thread, then the "blocking thread pool hack" is acceptable.
Note that this is not the best solution; the best solution is to go async all the way. But the blocking thread pool hack is an acceptable hack if you must call asynchronous code from synchronous code (again, it's "acceptable" only if GetWordsAsync is safe to call on a thread pool thread).
I would recommend using GetAwaiter().GetResult() rather than Result, in order to avoid the AggregateException wrapper on error. Also, the explicit type arguments are unnecessary, and you can elide async/await in this case:
var taskWords = Task.Run(() => GetWordsAsync(code));
return taskWords.GetAwaiter().GetResult();

Awaited async Task loses HttpContext.Current

I have a very bizarre situation regarding a Web Application that makes an asynchronous Http Post...
We have two branches in TFS. I merged code from one branch to another and then find that some Integration Tests in the new branch fail due to a System.NullReferenceException. I spend time ensuring that our code in both branches is identical, and all the referenced DLLs are identical too. Everything seems identical.
So, I decide to debug the test.
What our test does is to create a Mock IHttpClient object. We stub the Mock object in such a way that the clientMock.PostAsyncWithResponseMessage(x,y) returns a new HttpResponseMessage() object (on which we've set various properties).
So, the code looks like this:
using (var response = await client.PostAsyncWithResponseMessage(url, postData).ConfigureAwait(true))
{
if (response.IsSuccessStatusCode)
{
ret.Response = await response.Content.ReadAsStringAsync().ConfigureAwait(true);
ret.ContentType = response.Content.Headers.ContentType.ToString();
}
ret.StatusCode = response.StatusCode.ToInt();
}
Taking this a line at a time:
await client.PostAsyncWithResponseMessage(url, postData).ConfigureAwait(true))
This looks like it's an async method, but "client" is our Mock object so all it is doing is supporting the IHttpClient interface. If you inspect the Thread, the ID does not change when executing this line.
Later on, we have:
await response.Content.ReadAsStringAsync().ConfigureAwait(true);
Now, when this line executes, the HttpContext.Current is set to null - all our context is trashed. In this application, we do not call ConfigureAwait(false) anywhere, so as far as I'm aware there's no reason why we should lose the context.
If I change that line to:
response.Content.ReadAsStringAsync().Result;
Then this is of course blocking and we don't lose the context.
So two questions:
Why would the await method().ConfigureAwait(true) lose the context? [More marks will of course be awarded if one can also suggest why identical code from one TFS branch fails whilst working in a different branch, but I'm not expecting that]
I can see the obvious benefits of awaiting the .PostAsyncWithResponseMessage(url, postData) method since our thread would otherwise be blocked as the other server processed our request. However, having retrieved the data, what advantage is there in awaiting the ReadAsStringAsync()....in other words, is there a good reason not to use the .Result syntax?
thanks
If you inspect the Thread, the ID does not change when executing this line.
This does not necessarily mean that it ran synchronously. Most unit test frameworks provide a free-threaded context (SynchronizationContext.Current is null) and run their tests on a thread pool thread. It is entirely possible for the code to just happen to resume on the same thread (especially if you were only running one test).
Now, when this line executes, the HttpContext.Current is set to null - all our context is trashed. In this application, we do not call ConfigureAwait(false) anywhere, so as far as I'm aware there's no reason why we should lose the context.
I assume SynchronizationContext.Current is set to null, so there isn't actually a context. What's probably happening is that the test is setting HttpContext.Current (on some random thread pool thread), and after the first truly asynchronous operation, sometimes the test resumes on a thread where Current is set and sometimes it doesn't.
On ASP.NET, there's a request context (SynchronizationContext) that handles the propagation of HttpContext.Current. If you don't have something similar in your unit tests, then there's no context to preserve HttpContext.Current.
If you are looking for a quick fix, then you can probably use my AsyncContext type. This will provide a single-threaded context so that all your asynchronous code will resume on the same thread - not the same semantics as ASP.NET's context, but similar enough to be useful for some tests:
void TestMethod()
{
AsyncContext.Run(async () =>
{
// Test method body goes here.
});
}
On a side note, ConfigureAwait(true) is just noise; true is the default behavior.
is there a good reason not to use the .Result syntax?
It's not clear from your code that the server's response is actually read by the time PostAsyncWithResponseMessage completes. Based on the descriptions of your problem (and the fact that Result fixes it in your tests), it sounds like ReadAsStringAsync is in fact acting asynchronously.
If this is the case, then there are two good reasons not to block: 1) You're blocking a thread unnecessarily, and 2) You're opening yourself up to deadlock.

How to change the dart-sqlite code from synchronous style to asynchronous?

I'm trying to use Dart with sqlite, with this project dart-sqlite.
But I found a problem: the API it provides is synchronous style. The code will be looked like:
// Iterating over a result set
var count = c.execute("SELECT * FROM posts LIMIT 10", callback: (row) {
print("${row.title}: ${row.body}");
});
print("Showing ${count} posts.");
With such code, I can't use Dart's future support, and the code will be blocking at sql operations.
I wonder how to change the code to asynchronous style? You can see it defines some native functions here: https://github.com/sam-mccall/dart-sqlite/blob/master/lib/sqlite.dart#L238
_prepare(db, query, statementObject) native 'PrepareStatement';
_reset(statement) native 'Reset';
_bind(statement, params) native 'Bind';
_column_info(statement) native 'ColumnInfo';
_step(statement) native 'Step';
_closeStatement(statement) native 'CloseStatement';
_new(path) native 'New';
_close(handle) native 'Close';
_version() native 'Version';
The native functions are mapped to some c++ functions here: https://github.com/sam-mccall/dart-sqlite/blob/master/src/dart_sqlite.cc
Is it possible to change to asynchronous? If possible, what shall I do?
If not possible, that I have to rewrite it, do I have to rewrite all of:
The dart file
The c++ wrapper file
The actual sqlite driver
UPDATE:
Thanks for #GregLowe's comment, Dart's Completer can convert callback style to future style, which can let me to use Dart's doSomething().then(...) instead of passing a callback function.
But after reading the source of dart-sqlite, I realized that, in the implementation of dart-sqlite, the callback is not event-based:
int execute([params = const [], bool callback(Row)]) {
_checkOpen();
_reset(_statement);
if (params.length > 0) _bind(_statement, params);
var result;
int count = 0;
var info = null;
while ((result = _step(_statement)) is! int) {
count++;
if (info == null) info = new _ResultInfo(_column_info(_statement));
if (callback != null && callback(new Row._internal(count - 1, info, result)) == true) {
result = count;
break;
}
}
// If update affected no rows, count == result == 0
return (count == 0) ? result : count;
}
Even if I use Completer, it won't increase the performance. I think I may have to rewrite the c++ code to make it event-based first.
You should be able to write a wrapper without touching the C++. Have a look at how to use the Completer class in dart:async. Basically you need to create a Completer, return Completer.future immediately, and then call Completer.complete(row) from the existing callback.
Re: update. Have you seen this article, specifically the bit about asynchronous extensions? i.e. If the C++ API is synchronous you can run it in a separate thread, and use messaging to communicate with it. This could be a way to do it.
The big problem you've got is that SQLite is an embedded database; in order to process your query and provide your results, it must do computation (and I/O) in your process. What's more, in order for its transaction handling system to work, it either needs its connection to be in the thread that created it, or for you to run in serialized mode (with a performance hit).
Because these are fairly hard constraints, your plan of switching things to an asynchronous operation mode is unlikely to go well except by using multiple threads. Since using multiple connections complicates things a lot (as you can't share some things between them, such as TEMP TABLEs) let's consider going for a single serialized connection; all activity will be serialized at the DB level, but for an application that doesn't use the DB a lot it will be OK. At the C++ level, you'd be talking about calling that execute from another thread and then sending messages back to the caller thread to indicate each row and the completion.
But you'll take a real hit when you do this; in particular, you're committing to only doing one query at a time, as the technique runs into significant problems with semantic effects when you start using two connections at once and the DB forces serialization on you with one connection.
It might be simpler to do the above by putting the synchronous-asynchronous coupling at the Dart level by managing the worker thread and inter-thread communication there. That would let you avoid having to change the C++ code significantly. I don't know Dart well enough to be able to give much advice there.
Myself, I'd just stick with synchronous connection processing so that I can make my application use multi-threaded mode more usefully. I'd be taking the hit with the semantics and giving each thread its own connection (possibly allocated lazily) so that overall speed was better, but I do come from a programming community that regards threads as relatively heavyweight resources, so make of that what you will. (Heavy threads can do things that reduce the number of locks they need that it makes no sense to try to do with light threads; it's about overhead management.)

SignalR .Net client - how to invoke synchronously and asynchronously

I'm learning SignalR using the .Net client (not javascript), and was hoping for some clarification on how to invoke hub proxy methods in a synchronous or asynchronous manner.
Method with no return value
So far I've been doing something like this:-
myHubProxy.Invoke("DoSomething");
I've found this to be asynchronous, which is fine as it's effectively "fire-and-forget" and doesn't need to wait for a return value. A couple of questions though:-
Are there any implications with wrapping the Invoke in a try..catch block, particularly with it being asynchronous? I might want to know if the call failed.
Are there any scenarios where you would want to call a method that doesn't return a value synchronously? I've seen the .Wait() method mentioned, but I can't think why you would want to do this.
Method with return value
So far I've been using the Result property, e.g.:-
var returnValue = myHubProxy.Invoke<string>("DoSomething").Result;
Console.WriteLine(returnValue);
I'm assuming this works synchronously - after all, it couldn't proceed to the next line until a result had been returned. But how do I invoke such a method asynchronously? Is it possible to specify a callback method, or should I really be using async/await these days (something I confess to still not learning about)?
If you want to write asynchronous code, then you should use async/await. I have an intro on my blog with a number of followup resources at the end.
When you start an asynchronous operation (e.g., Invoke), then you get a task back. The Task type is used for asynchronous operations without a return value, and Task<T> is used for asynchronous operations with a return value. These task types can indicate to your code when the operation completes and whether it completed successfully or with error.
Although you can use Task.Wait and Task<T>.Result, I don't recommend them. For one, they wrap any exceptions in an AggregateException, which make your error handling code more cumbersome. It's far easier to use await, which does not do this wrapping. Similarly, you can register a callback using ContinueWith, but I don't recommend it; you need to understand a lot about task schedulers and whatnot to use it correctly. It's far easier to use await, which does the (most likely) correct thing by default.
The .Result property returns a async Task, so the server requests is still performed async.
There is not reason to hold up a thread for the duration of the call thats why you use async.
If you fire the call on the GUI thread its even more important todo it async because otherwise the GUI will not respond while the call is done
1) Yuo need to use the await keyword if you want try catch blocks to actually catch server faults. Like
try
{
var foo = await proxy.Invoke<string>("Bar");
}
catch (Exception ex)
{
//act on error
}
2) I think you ment to ask if its any reason to call it async? And yes like I said, you do not want to block any threads while the request is being made

Confused by TaskScheduler and SynchronizationContext for sync-on-async, can't control the sync context?

The Issue
I have an ASP.NET 4.0 WebForms page with a simple web-service WebMethod. This method is serving as a synchronous wrapper to asynchronous / TPL code. The problem I'm facing, is that the inner Task sometimes has a null SynchronizationContext (my preference), but sometimes has a sync context of System.Web.LegacyAspNetSynchronizationContext. In the example I've provided, this doesn't really cause a problem, but in my real-world development scenario can lead to dead-locks.
The first call to the service always seems to run with null sync context, the next few might too. But a few rapid-fire requests and it starts popping onto the ASP.NET sync context.
The Code
[WebMethod]
public static string MyWebMethod(string name)
{
var rnd = new Random();
int eventId = rnd.Next();
TaskHolder holder = new TaskHolder(eventId);
System.Diagnostics.Debug.WriteLine("Event Id: {0}. Web method thread Id: {1}",
eventId,
Thread.CurrentThread.ManagedThreadId);
var taskResult = Task.Factory.StartNew(
function: () => holder.SampleTask().Result,
creationOptions: TaskCreationOptions.None,
cancellationToken: System.Threading.CancellationToken.None,
scheduler: TaskScheduler.Default)
.Result;
return "Hello " + name + ", result is " + taskResult;
}
The definition of TaskHolder being:
public class TaskHolder
{
private int _eventId;
private ProgressMessageHandler _prg;
private HttpClient _client;
public TaskHolder(int eventId)
{
_eventId = eventId;
_prg = new ProgressMessageHandler();
_client = HttpClientFactory.Create(_prg);
}
public Task<string> SampleTask()
{
System.Diagnostics.Debug.WriteLine("Event Id: {0}. Pre-task thread Id: {1}",
_eventId,
Thread.CurrentThread.ManagedThreadId);
return _client.GetAsync("http://www.google.com")
.ContinueWith((t) =>
{
System.Diagnostics.Debug.WriteLine("Event Id: {0}. Continuation-task thread Id: {1}",
_eventId,
Thread.CurrentThread.ManagedThreadId);
t.Wait();
return string.Format("Length is: {0}", t.Result.Content.Headers.ContentLength.HasValue ? t.Result.Content.Headers.ContentLength.Value.ToString() : "unknown");
}, scheduler: TaskScheduler.Default);
}
}
Analysis
My understanding of TaskScheduler.Default is that it's the ThreadPool scheduler. In other words, the thread won't end up on the ASP.NET thread. As per this article, "The default scheduler for Task Parallel Library and PLINQ uses the .NET Framework ThreadPool to queue and execute work". Based on that, I would expect the SynchronizationContext inside SampleTask to always be null.
Furthermore, my understanding is that if SampleTask were to be on the ASP.NET SynchronizationContext, the call to .Result in MyWebMethod may deadlock.
Because I'm not going "async all the way down", this is a "synchronous-on-asynchronous" scenario. Per this article by Stephen Toub, in the section titled "What if I really do need “sync over async”?" the following code should be a safe wrapper:
Task.Run(() => holder.SampleTask()).Result
According to this other article, also by Stephen Toub, the above should be functionally equivalent to:
Task.Factory.StartNew(
() => holder.SampleTask().Result,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
Thanks to being in .NET 4.0, I don't have access to TaskCreationOptions.DenyChildAttach, and I thought this was my issue. But I've run up the same sample in .NET 4.5 and switched to TaskCreationOptions.DenyChildAttach and it behaves the same (sometimes grabs the ASP.NET sync context).
I decided then to go closer to the "original" recommendation, and implement in .NET 4.5:
Task.Run(() => holder.SampleTask()).Result
And this does work, in that it always has a null sync context. Which, kind of suggests the Task.Run vs Task.Factory.StartNew article has it wrong?
The pragmatic approach would be to upgrade to .NET 4.5 and use the Task.Run implementation, but that would involve development time that I'd rather spend on more pressing issues (if possible). Plus, I'd still like to figure out what's going on with the different TaskScheduler and TaskCreationOptions scenarios.
I've coincidentally found that TaskCreationOptions.PreferFairness in .NET 4.0 appears to behave as I'd wish (all executions have a null sync context), but without knowing why this works, I'm very hesitant to use it (it may not work in all scenarios).
Edit
Some extra info... I've updated my sample code with one that does deadlock, and includes some debug output to show what threads the tasks are running on. A deadlock will occur if either the pre-task or continuation-task outputs indicate the same thread id as the WebMethod.
Curiously, if I don't use ProgressMessageHandler, I don't seem able to replicate the deadlock. My impression was that this shouldn't matter, that regardless of down-stream code, I should be able to safely "wrap" an asynchronous method up in a synchronous context using the right Task.Factory.StartNew or Task.Run method. But this doesn't seem to be the case?
First, using sync-over-async in ASP.NET often doesn't make much sense. You're incurring the overhead of creating and scheduling Tasks, but you don't benefit from it in any way.
Now, to your question:
My understanding of TaskScheduler.Default is that it's the ThreadPool scheduler. In other words, the thread won't end up on the ASP.NET thread.
Well, ASP.NET uses the same ThreadPool too. But that's not really relevant here. What's relevant is that if you Wait() (or call Result, that's the same) on a Task that's scheduled to run (but didn't start yet), the TaskScheduler my decide to just run your Task synchronously. This is known as “task inlining”.
What this means is that your Task ends up running on the SynchronizationContext, but it wasn't actually scheduled through it. This means there is actually no risk of deadlocks.
Thanks to being in .NET 4.0, I don't have access to TaskCreationOptions.DenyChildAttach, and I thought this was my issue.
This has nothing to do with DenyChildAttach, there are no Tasks that would be AttachedToParent.
I've coincidentally found that TaskCreationOptions.PreferFairness in .NET 4.0 appears to behave as I'd wish (all executions have a null sync context), but without knowing why this works, I'm very hesitant to use it (it may not work in all scenarios).
This is because PreferFairness schedules the Task to the global queue (instead of the thread-local queue that each ThreadPool thread has), and it seems Tasks from the global queue won't be inlined. But I wouldn't rely on this behavior, especially since it can change in the future.
EDIT:
Curiously, if I don't use ProgressMessageHandler, I don't seem able to replicate the deadlock.
There's nothing curious about that, that's exactly your problem. ProgressMessageHandler reports progress on the current synchronization context. And because of task inlining, that is the ASP.NET context, which you're blocking by waiting synchronously.
What you need to do is to make sure GetAsync() is run on a thread without the synchronization context set. I think the best way to do that is to call SynchronizationContext.SetSynchronizationContext(null) before calling GetAsync() and restoring it afterwards.

Resources