What would be the most correct way to use async method in databound property getter? I am talking about solid, scientific arguments, not personal preferences. I've read many threads about the problem, but not this specific case. Some of the solutions don't work in all the cases, and some of the suggestion, well... they were just too subjective or just wrong.
What I don't accept and why:
You can't - Actually, it is possible. There are many posts like "there are no such things like async properties", "it is against the design of the language" etc. but also there are many sensible explanations why such expressions are false
This should me method, not property - It can't be. I want to databind it. I provide property "proxies" for people using this code because in the future there may be different method to calculate this pseudo-property. And I want the View-side of the binding to be simple as possible
Use property to store the cached result of the method - that would defeat the purpose, it is actually something that changes dynamically and the class is an ORM Entity so it would store redundant data to the DB.
Use SomeTask.Result; or SomeTask.GetAwaiter().GetResult() - In most cases I would just use it. I've successfully used those in many cases i.e. Console applications. It's nice, clear and easily readable. But when I use it in databound property I get a deadlock
Problem background (simplified)
Let's say that I am responsible for developing ORM mechanism in a project. There was a first stable version, but now I want to add some properties to the Entities for the DataBinders who are responsible for the layout. I can edit Entity layer, but I can't edit Mapping and Repository layers. (I am not held againt my will, this situation is fictional simplification). All the methods in repositories are async. All I can do is ask someone responsible to provide identical synchronous methods for all of the methods, but it would be stupid to this kind of redundant work.
Only solution I can use now
_something = Task.Run(async () => await AnotherRepository.CalculateStuff(this)).Result;
And it just doesn't look right to me. It works, but I have to await my method inside the lambda in Task.Run(). I am stuck with it for the time being, and I want to know the simplest and correct approach.
Repository method pseudo-code
public async static Task<IList<CalculatedStuff>> CalculateStuff(SomeClass class)
{
return await Task.Run(() =>
{
using (var session = Helper.OpenSession())
return session.CreateCriteria(typeof(CalculatedStuff)).Add(Restrictions.Eq("SomeClass", class))
///...
.List<CalculatedStuff>();
});
}
there are no such things like async properties
I have a blog post and MSDN article on "async properties" for data binding. I do take the stance that they are not natural, which is based on these (objective) observations:
Properties read by data binding must return immediately (synchronously).
Asynchronous operations are asynchronous (that is, they complete after some time).
Clearly, these are at complete odds with one another.
Now, there are a few different solutions, but any solution that attempts to violate one of these observations is going to be dubious, at best.
For example, you can attempt to violate the second observation by trying to run the asynchronous operation synchronously. As you discovered, Result / Wait / GetAwaiter().GetResult() will deadlock (for reasons described in detail on my blog). Task.Run(() => ...).GetAwaiter().GetResult() will avoid the deadlock but will execute the code in a free-threaded context (which is OK for most code but not all). These are two different kinds of sync-over-async; I call them the "Blocking Hack" and the "Thread Pool Hack" in my Async Brownfield article, which also covers two other kinds of sync-over-async patterns.
Unfortunately, there is no solution for sync-over-async that works in every scenario. Even if you get it to work, your users would get a substandard experience (blocking the UI thread for an indefinite amount of time), and you may have problems with app stores (I believe MS's at least will actively check for blocking the UI thread and auto-reject). IMO, sync-over-async is best avoided.
However, we obviously cannot violate the first observation, either. If we're data binding to the result of some asynchronous operation, we can't very well return it before the operation completes!
Or can we?
What if we change what the data binding is attaching to? Say, introduce a property that has a default value before the operation is completed, and changes (via INotifyPropertyChanged) to the result of the operation when the operation completes. That sounds reasonable... And we can stick in another property to indicate to the UI that the operation is in progress! And maybe another one to indicate if the operation failed...
This is the line of thinking that resulted in my NotifyTaskCompletion type in the article on data binding (updated NotifyTask type here). It is essentially a data-bindable wrapper for Task<T>, so the UI can respond dynamically to the asynchronous operation without trying to force it to be synchronous.
This does require some changes to the bindings, but you get a nice side effect that your UX is better (non-blocking).
This should me method, not property
Well, you can do this as a property:
TEntity Entity { get { return NotifyTask.Create(() => Repository.GetEntityAsync()); } }
// Data bind to Entity.Result for the results.
// Data bind to Entity.IsNotCompleted for a busy spinner.
However, I would say that it's surprising behavior to have a property read kick off something significant like a database query or HTTP download. That's a pretty wide definition of "property". IMO, this would be better represented as a method, which connotates action more than a property does (or perhaps as part of an asynchronous initialization, which I also describe on my blog). Put another way: I prefer my properties without side effects. Reading a property more than once and having it return different values is counterintuitive. This final paragraph is entirely my own opinion. :)
If you have access to the source code of AnotherRepository.CalculateStuff, you can implement it in a way that won't deadlock when called from bound property. First short summary of why it deadlocks. When you await something, current synchronization context is remembered and the rest of the method (after async) is executed on that context. For UI applications that means the rest of the method is executed on UI thread. But in your case UI thread is already blocked by waiting for the Result of task - hence deadlock.
But there is method of Task named ConfigureAwait. If you pass false for it's only argument (named continueOnCapturedContext) and await task returned by this method - it won't continue on captured context, which will solve your problem. So suppose you have:
// this is UI bound
public string Data
{
get { return GetData().Result; }
}
static async Task<string> GetData() {
await Task.Run(() =>
{
Thread.Sleep(2000);
});
return "test!";
}
This will deadlock when called from UI thread. But if you change it:
static async Task<string> GetData() {
await Task.Run(() =>
{
Thread.Sleep(2000);
}).ConfigureAwait(false);
return "test!";
}
It won't any more.
For those who might read this later - don't do it this way, only if for temporary debugging purposes. Instead return dummy object from your property getter with some IsLoading flag set to true, and meanwhile load data in background and fill dummy object properties when done. This will not freeze your UI during long blocking operation.
Related
I have the following code:
var things = await GetDataFromApi(cancellationToken);
var builder = new StringBuilder(JsonSerializer.Serialize(things));
await things
.GroupBy(x => x.Category)
.ToAsyncEnumerable()
.SelectManyAwaitWithCancellation(async (category, ct) =>
{
var thingsWithColors = await _colorsApiClient.GetColorsFor(category.Select(thing => thing.Name).ToList(), ct);
return category
.Select(thing => ChooseBestColor(thingsWithColors))
.ToAsyncEnumerable();
})
.ForEachAsync(thingAndColor =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // prints different IDs
builder.Replace(thingAndColor.Thing, $"{thingAndColor.Color} {thingAndColor.Thing}");
}, cancellationToken);
It uses System.Linq.Async and I find it difficult to understand.
In "classic"/synchronous LINQ, the whole thing would get executed only when I call ToList() or ToArray() on it. In the example above, there is no such call, but the lambdas get executed anyway. How does it work?
The other concern I have is about multi-threading. I heard many times that async != multithreading. Then, how is that possible that the Console.WriteLine(Thread.CurrentThread.ManagedThreadId); prints various IDs? Some of the IDs get printed multiple times, but overall there are about 5 thread IDs in the output. None of my code creates any threads explicitly. It's all async-await.
The StringBuilder does not support multi-threading, and I'd like to understand if the implementation above is valid.
Please ignore the algorithm of my code, it does not really matter, it's just an example. What matters is the usage of System.Async.Linq.
ForEachAsync would have a similar effect as ToList/ToArray since it forces evaluation of the entire list.
By default, anything after an await continues on the same execution context, meaning if the code runs on the UI thread, it will continue running on the UI thread. If it runs on a background thread, it will continue to run on a background thread, but not necessarily the same one.
However, none of your code should run in parallel. That does not necessarily mean it is thread safe, there probably need to be some memory barriers to ensure data is flushed correctly, but I would assume these barriers are issued by the framework code itself.
The System.Async.Linq, as well as the whole dotnet/reactive repository, is currently a semi-abandoned project. The issues on GitHub are piling up, and nobody answers them officially for almost a year. There is no documentation published, apart from the XML documentation in the source code on top of each method. You can't really use this library without studying the source code, which is generally easy to do because the code is short, readable, and honestly doesn't do too much. The functionality offered by this library is similar with the functionality found in the System.Linq, with the main difference being that the input is IAsyncEnumerable<T> instead of IEnumerable<T>, and the delegates can return values wrapped in ValueTask<T>s.
With the exception of a few operators like the Merge (and only one of its overloads), the System.Async.Linq doesn't introduce concurrency. The asynchronous operations are invoked one at a time, and then they are awaited before invoking the next operation. The SelectManyAwaitWithCancellation operator is not one of the exceptions. The selector is invoked sequentially for each element, and the resulting IAsyncEnumerable<TResult> is enumerated sequentially, and its values yielded the one after the other. So it's unlikely to create thread-safety issues.
The ForEachAsync operator is just a substitute of doing a standard await foreach loop, and was included in the library at a time when the C# language support for await foreach was non existent (before C# 8). I would recommend against using this operator, because its resemblance with the new Parallel.ForEachAsync API could create confusion. Here is what is written inside the source code of the ForEachAsync operator:
// REVIEW: Once we have C# 8.0 language support, we may want to do away with these
// methods. An open question is how to provide support for cancellation,
// which could be offered through WithCancellation on the source. If we still
// want to keep these methods, they may be a candidate for
// System.Interactive.Async if we consider them to be non-standard
// (i.e. IEnumerable<T> doesn't have a ForEach extension method either).
With async turtles all the way down ...
Some of the background research:
Async/Await - Best Practices in Asynchronous Programming
Async
In code I've seen:
Developers wrap code in a Task.Run() upon entering a method and awaiting it to force it to be async or (or older .NET 4.0 TaskFactory.StartNew())
I've personally just left it synchronous (but it partially violates turtles all the down as different branches often are sync)
I've also seen the attempt to use ValueTask to short-circuit the return as async given the nature of ValueTask with a return value being akin to:
return new ValueTask<int>(valueWantToReturn);
Example psudeo code:
public async Task ParentMethodAsync()
{
// ... do something upon entering
int neededValue = SyncNestedDryMethod(); // ** this part **
await _nthLayer.DoSomethingWithRepoAsync(); // ** same concept applies here
// if there is no asyncronous logic required **
// ... do anything else needed
}
public int SyncNestedDryMethod()
{
// ... do something that requires no real async method signature
// declaration because it is straight synchronous logic (covers reusing
// code for DRY purposes, method-level SRP abstraction (includes moving it
// to an abstracted class -- for future readers), etc.)
// I've seen making the method async then awaiting Task.Run() or
// Task.StartFactory.New() inside this (sync changed to async method)
// to try and force it to be async or last line being:
// return new ValueTask<int>(valueWantToReturn);
// but everything above it being only syncronous logic
}
Is there a best practice to be aware of not found addressed in the respective links (or overlooked) or elsewhere which I have not come across to address abstracting synchronous code into new methods (for DRY purposes, SRP, etc.) that do not have the ability to be async or are forced async all the while following async through and through?
Your question isn't entirely clear, but I think you're asking how to run synchronous code in an asynchronous way? If so, the answer is: you can't.
Using Task.Run() doesn't make the code asynchronous. It just runs the code on a different thread and gives you an asynchronous way to wait for that thread to complete. That may be what you need if you just need to get the work off of the current thread. For example, you would use that in a desktop application where you want to get the work off of the UI thread. But this wouldn't help you at all in ASP.NET.
ValueTask is used for cases where the work might be done asynchronously, but also may complete synchronously too. For example, if data is usually returned from an in memory cache, but refreshing that cache is done asynchronously. This is described in detail here. But if the work is always synchronous, then there is no point using ValueTask, or Task or async.
I feel like I have read thousands of SO questions and blog posts and MSDN articles about this stuff, but I'm still not "getting" it completely. So please help me out.
At my work, we have an ASP.NET application that HAS to get data from a sync method. I have no control over this method and I have no idea as to how it is implemented.
I have an async controller method that is calling 3 other async services, I can use async "all the way down" (yay!). But this last one is not async and will likely never be. Worse, it takes the longest. I would love to be able to start tasks for all the services, and await them all. From what I have been able to piece together, I have the following options available to me, and I think I understand most of the consequences, but would like confirmation and clarification where necessary.
So, given the method:
public async Task<Thing> GetThing()
{
var task1 = GetProp1Async(); // etc.
var syncResult = ......
myThing.Prop1 = await task1;
myThing.SyncProp = .......
return myThing;
}
The options I have for filling in those dots could be:
Option 1:
Just call the method synchronously. This will block my current thread. My other tasks can all be running, and I can await them later, but I am going to block here, inside my async method.
var syncResult = GetSyncResult();
Option 2:
Use Task.Run().Result. I understand this is not ideal at all, as I will spawn a new thread, while also blocking my original thread, which I think is the worst case here, right? HOWEVER, I will NOT get the deadlock issue, since I'm forcing a
new thread, right?
var syncResult = Task.Run(() => GetSyncResult()).Result;
Option 3:
I THINK this is the best option? My async code won't block a thread, but I'm still spawning a new thread that will go do sync work. So, this feels like a net-zero gain. I still have 1 thread that's doing stuff, and possibly waiting, but that still may be my best option?
var syncResult = await Task.Run(() => GetSyncResult());
Option 4:
I still don't understand ConfigureAwait(false), but I could try it. What does this get me? It seems that some posts say "do this in all the places!" Some say "don't do this to avoid deadlocks". Others say, if you do it, do it "all the way down". Well, I have no idea what GetSyncResult() does, so I have no idea if it calls any async stuff behind the scenes (I mean, it probably doesn't, but I don't KNOW for sure). So could that come back to bite me?
var syncResult = await Task.Run(() => GetSyncResult()).ConfigureAwait(false);
So what is my best option here? Did I miss any options? Worse, did I miss the best option?
I know these questions have been asked and answered to death, but, I'm just not getting my dots connected, and I definitely need some help.
The options depend a lot on the context of your code.
If your code (GetThing() in your example, which should really be GetThingAsync), is either a classic ASP.NET action or an event handler for a UI application, which based on your answer, I think it is, then you are an important thread, usually limited in number, so it's important that you not block this particular thread because it's special. Option 3 is the best answer here, because it frees up the important thread to let it get back to UI/Web stuff, and shunts the work off to a non-important thread pool thread. But, importantly, re-enters the important context when the expensive work is done so you can do things like access the HttpContext or UI elements.
If your code is in some library others are going to use and it's super important you never block the thread, option 4 is the "right" answer. As you've said, there are dozens of blog posts on the internet that go in to varying levels of details as to what those do, so I won't repeat them all here, since you've already read them. It's up to your caller to decide to attempt to renter the important thread context when they call you by calling ConfigureAwait(false) (to not re-enter it), or just awaiting it straight (which will re-enter it).
Option 1 is the easiest and least likely to have some unexpected bug. Unless you are having capacity issues on your ASP.NET application and you know this call is what's doing it, I'd recommend sticking with the simple one. You can always add complexity later, but bugs in async code can be very painful to track down, so trying to do it the "right" way first instead of the simple way might cost more than it's worth in the end until you know it's really a problem, and not just a theoretical one.
I'm looking at some code written a while back that is making me very nervous. The general shape of the methods in questions is like this;
public Task Foo(...){
SyncMethod();
SyncMethod();
...
return AsyncMethod();
}
I realize I can just mark the method async and do an await on the last call, but...do I have to? Is this safe to use as is? The sync methods that are called before the last async method do not have asynchronous alternatives and the Foo method does not care about the result of the AsyncMethod, so it looks like it's ok to just return the awaitable to the caller and let the caller deal with it.
Also, FWIW, the code in question might be called from a thread that's running with an active ASP.NET context, so I'm getting that tingling feeling in my brain that there's some invisible evil that I'm not seeing here?
I realize I can just mark the method async and do an await on the last call, but...do I have to?
Actually, if you did this, the only change that it would have is that exceptions thrown by either of those synchronous methods would be wrapped into the returned Task, while in the current implementation the method would throw without ever successfully returning a Task. The actual effect of what work is done synchronously and what work is done asynchronously is entirely unaffected.
Having said that, both of the options you've mentioned are worrisome. Here you have a method that appears to be asynchronous, meaning someone calling it expects it to return more or less right away, but in reality the method will run synchronously for some amount of time.
If your two synchronous methods are really fast and as a result, you're confident that this very small amount of synchronous work won't be noticeable to any of your callers, then that's fine. If, however, that work will (even potentially) take a non-trivial amount of time to solve, then you have a problem on your hands.
Having actually asynchronous alternatives for those methods would be best, but as a last resort, until you have a better option, often the best you can manage to do is to await Task.Run(() => SyncMethod()); for those methods (which of course means the method now needs to be marked as async).
I'm involved in porting some code over to a Windows Store Library.
It would be convenient for us to be able to sometimes wait for the results of an asynchronous operation before continuing. I thought we had the answer with Task's Result property, but for some reason it crashes my app.
I made a quick Windows Store test App like so:
public MainPage()
{
this.InitializeComponent();
MyTextBox.Text = "0";
var a = ReturnIntMax();
MyTextBox.Text = "1";
MyTextBox.Text = a.Result.ToString();
}
public async Task<int> ReturnIntMax()
{
await Task.Delay(1000);
return 5;
}
As far as I understand the Result property, this should work, so I hope somebody can tell me what's going on. I'm not interested in why this is bad design. We're dealing with a lot of comm traffic and we can't allow conflicts. If necessary, we can work around this, but first I want to understand why its not working. If it's just unsupported to call Result from a synchronous context, I would have thought it would give me a compiler error.
I describe the underlying cause of the deadlock on my blog. This is not a compiler error for several reasons; e.g., it's a violation of separation of concerns to ask a compiler (which is responsible for translating C# to IL) to understand the threading models of various user interface frameworks. Also, it's not practical to add an error for each call to Result that might be on a UI thread.
As a general rule, do not use Task.Wait or Task.Result at all. Instead, find a way to structure your code so that it's asynchronous. This can be awkward, but in the end you'll find that you end up with a better UI design (i.e., instead of blocking the UI while the main page loads, you need to design a blank or "loading..." page that can be shown immediately and then transition to show the data). My blog posts on constructors and properties have some ideas on how to make them async-friendly.