UI Received task got cancelled [duplicate] - c#

This question already has answers here:
'await' works, but calling task.Result hangs/deadlocks
(6 answers)
Closed 3 years ago.
In my application, I am trying to update the user profile which calls the Rest API. API has one sync method UpdateProfile where execution getting stuck.
this line of code is ending the execution
command.UserProfile.LookupItems = GetLookupItemsByUserId(existingUser.Id).Result;
When i changed this line of code to
command.UserProfile.LookupItems = Task.Run(async () => await GetLookupItemsByUserId(existingUser.Id)).Result;
It started working without any issue.Can anybody explain to me what is going on behind the scene?

The first version is blocking the current thread, when the task complete the blocked thread cannot catch it.
YourType Signature() {
var neverUsedValue = task.Result;
}
The second one is yielding the current "thread" until the task is returned.
YourType Signature() {
var value = Task.Run(await => async MethodThatWillComplete()).Result
}
What you should do is propagate the async to the method:
async Task<YourType> SignatureAsync() {
command.UserProfile.LookupItems = await GetLookupItemsByUserId(existingUser.Id);
}
In this way you will avoid handling the AggregateException.

There is very well written article on this here:Don't block async
In a few words, blocking on async code is bad because it may be blocking the thread which is supposed to run the async code and thus generete a deadlock.

Related

Await doesn't block calling thread [duplicate]

This question already has answers here:
How and when to use ‘async’ and ‘await’
(25 answers)
How do yield and await implement flow of control in .NET?
(5 answers)
Brief explanation of Async/Await in .Net 4.5
(3 answers)
Closed 2 years ago.
I never had a good chance to go deep into async/await , so I have just a gist of what it does.
So I tried it in WinForms app like this:
private async void button2_Click(object sender, EventArgs e)
{
// In below line I understand the Task is created and scheduled to execute, which in this
// simple case means, that it executes right away asynchronously.
var task = Task.Factory.StartNew(() =>
{
Task.Delay(5000).Wait();
return 12;
});
// Here we wait for the task to finish, so we don't see MessageBox yet.
var res = await task;
MessageBox.Show("Result is :" + res);
}
My question is, since we are waiting on await I expected to block UI thread, since we can go any further in that thread (to the line with MessageBox). So UI thread actually stops on method with event hadnler.
But, to my surprise, windows is responsive and everything works very well, but I didn't expect that. Can anybody explain me what is going on?
After reading this post, I still have a doubt, if await is asynchronous and doesn't block UI thread in my example, why the thread doesn't proceed to next line with MessageBox? How the UI thread proceeds then?
Is good idea that code after await is just another Task, like in ContinueWith? But it comes back to UI context?
Async methods are a lot like generator methods. The compiler will split up your code at each await operator. A block of code is inserted to check if the task is already complete, in which case the method immediately continues. Or if the task is not complete, a callback is registered to continue execution later, and your method returns.
Returning early is the whole point of an async method.

Multiple Task.Run vs no await for async method? [duplicate]

This question already has answers here:
When should you use Task.Run() rather than await?
(2 answers)
is using an an `async` lambda with `Task.Run()` redundant?
(3 answers)
What difference does it make - running an 'async' action delegate with a Task.Run (vs default action delegate)?
(2 answers)
Closed 3 years ago.
I have some IO-Bound jobs(periodically write some data to file) codes as follows:
public async Task SaveToFile1(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
public async Task SaveToFile2(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
public async Task SaveToFile3(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
The caller is the main method.
The tasks worked fine and produced the correct result when I run them with 2 ways as follows:
void main ()
{
// other codes
// way 1:
SaveToFile1(1000);
SaveToFile2(1000);
SaveToFile3(1000);
// other codes will not let the app exit
}
void main ()
{
// other codes
// way 2:
Task.Run(async() => await SaveToFile1(1000));
Task.Run(async() => await SaveToFile2(1000));
Task.Run(async() => await SaveToFile3(1000));
// other codes will not let the app exit
}
Which is the right way or another way is the best choice for my situation?
Thanks for your answers!
Edit:
In way 1, when await Task.Delay 'complete', a new thread-pool thread may be captured to execute the loop's next step, ..., loop will always running in other thread at the await hit.
In way 2, may be a new thread-pool thread will be used when Task.Run execute immediately, loop will always running in other thread at the begin.
The result are the same, where is the diffrence?
So my question is not about Task.Run vs async-await!
Asynchronous code allows the current thread to be freed to do other work while waiting for a response from something else. But all the code before the first await will be done on the same thread you call it from. If that code is significantly CPU-heavy, it could be noticeable.
If you don't use Task.Run, the method will be run on the same thread up until the first asynchronous I/O request, when it will return a Task and your next method will be called.
Task.Run will execute the code on a different thread. This is good if it does do some CPU-heavy work and you don't want that done on the current thread (like in a desktop app where you don't want it done on the UI thread). But there is a small cost to starting up a new thread too.
Whether using Task.Run will make any noticeable difference depends on the type of app you're writing and what your methods do.
It's fine if you don't await them immediately, but if you don't ever await them, then you will never know when they finished, if they finished successfully, or threw and exception. This is called "fire and forget". Do that only if you don't care if they succeed.
Instead, you can wait at the end to make sure they completed successfully. For example:
void main ()
{
// other codes
var taskList = new List<Task>();
taskList.Add(SaveToFile1(1000));
taskList.Add(SaveToFile2(1000));
taskList.Add(SaveToFile3(1000));
// other codes will not let the app exit
// wait till everything finishes before exiting
await Task.WhenAll(taskList);
}

Task.Run how it works [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I guess it's simple but I have some misunderstanding in the work of tasks
When I call the code below it's works well, I get a result in about 1 sec.
return Task.Run(() => SendRequest<IADsystem[]>(path)).Result;
But this one never returns a result:
Task<IADsystem[]> task = SendRequest<IADsystem[]>(path);
task.Wait(); //also tried without wait
return task.Result;
I thought maybe the task didn't start and I need to call Start(), but when I made it I got "Start may not be called on a promise-style task" exception.
SendRequest method:
private async Task<T> SendRequest<T>(string requestUri) where T : class
{
var authHandler = new HttpClientHandler();
authHandler.Credentials = CredentialCache.DefaultNetworkCredentials;
using(var client = new HttpClient(authHandler))
{
client.BaseAddress = apiServerURI;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(jsonAcceptType);
HttpResponseMessage response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsAsync<T>();
}
else
return null;
}
}
Please, explain how it works
Consider the Wait() approach first:
Task<IADsystem[]> task = SendRequest<IADsystem[]>(path);
task.Wait(); //also tried without wait
return task.Result;
This code is using the sync-over-async antipattern. This can cause a deadlock, as I describe in detail on my blog. The core problem is that your code is blocking on asynchronous code. This works in some scenarios, but in this case you're seeing the common deadlock.
In summary, this is due to await capturing the current context (usually a SynchronizationContext), and using that to resume its async method. Thus, if you call this code from a UI thread (or ASP.NET request context), then the awaits inside SendRequest will attempt to resume on that context, but the context is blocked by the Wait/Result, resulting in deadlock.
Note that the problem is due to synchronously calling an asynchronous method; the ideal solution is to go "async all the way", as I describe in my async best practices article.
Back to the actual question:
Task.Run how it works
When I call the code below it's works well
return Task.Run(() => SendRequest<IADsystem[]>(path)).Result;
Sort of. It "works" in the sense that it does not deadlock. However, it's not ideal because it blocks a thread pool thread for the duration of the request. A better solution would be to use async all the way.
But leaving that aside for the moment, the reason why it works is because it "steps outside" the calling context. Task.Run executes the SendRequest on a thread pool thread (one without a UI or ASP.NET request context), and as such the awaits in SendRequest resume on thread pool threads. This is why your calling thread can block on it without deadlocking.
But it still shouldn't block on the task; it should await it instead.
async/await methods must be async/await all the way through. If you are using Windows Forms, then whatever event handler contains the code that calls SendRequest must be marked as async. Every method between the UI event handler and your SendRequest must also be marked async, and they must be awaited. You should then
var result = await SendRequest<IADsystem[]>(path);
like Fabio suggests.
Here is some more information about async/await.
I started learning about async here in this page so I assume it is good starting point. I urge you to look at execution context Async - Starting Point
Coming to why you have a dead lock, I will try to explain. When you called task.Wait(), you are basically telling your current thread to wait for the result to continue. So right now your current thread, or your Execution Context is waiting for the result to continue. Let us continue. When you called task.Wait(), you entered private async Task<T> SendRequest<T>(string requestUri)... method and the moment you reached return await response.Content.ReadAsAsync<T>(); you passed your current execution context, which is waiting the result from SendRequest<T>. Right now, you are in a dead lock. Why? Your UI thread is waiting an answer from SendRequest<T> and in order for SendRequest<T> to finish (or return), it needs to access to UI thread but you can not access the UI thread because it is waiting for SendRequest<T> to finish but for SendRequest<T> to finish it needs to access to UI thread....

What is the difference between WaitAll and WhenAll? [duplicate]

This question already has answers here:
WaitAll vs WhenAll
(4 answers)
Closed 6 years ago.
I have this code:
List<ComponentesClasificaciones> misClasificaciones = new List<ComponentesClasificaciones>();
Task tskClasificaciones = Task.Run(() =>
{
misClasificaciones = VariablesGlobales.Repositorio.buscarComponentesClasificacionesTodosAsync().Result;
});
Task.WhenAll(tskClasificaciones);
List<ComponentesClasificaciones> misVClasificacionesParaEstructuras = new List<ComponentesClasificaciones>(misClasificaciones);
If I use Task.WhenAll, misClasificaciones does not have any element but when I use awit all I get all the elements that I request to the database.
When to use WhenAll and when to use WaitAll?
MSDN does a good job of explaining this. The difference is pretty unambiguous.
Task.WhenAll:
Creates a task that will complete when all of the supplied tasks have completed.
Task.WaitAll:
Waits for all of the provided Task objects to complete execution.
So, essentially, WhenAll gives you a task that isn't done until all of the tasks you give it are done (and allows program execution to continue immediately), whereas WaitAll just blocks and waits for all of the tasks you pass to finish.
WhenAll returns a task that you can ContinueWith once all the specified tasks are complete. You should be doing
Task.WhenAll(tskClasificaciones).ContinueWith(t => {
// code here
});
Basically, use WaitAll when you want to synchronously get the results, use WhenAll when you want to start a new asynchronous task to start some more processing

Using httpclient in MVC application [duplicate]

This question already has answers here:
HttpClient.GetAsync(...) never returns when using await/async
(7 answers)
Closed 9 years ago.
When I invoke below function in a console app, it just works. But when I add the same to a MVC controller, execution never reaches JsonConvert line. Any idea, what I am missing.
Calling code
GetVersion(url).Result.FileVersion
Method
public static async Task<Version> GetVersion(string url, string hostHeader)
{
var client = new HttpClient();
if (!string.IsNullOrEmpty(hostHeader))
{
client.DefaultRequestHeaders.Host = hostHeader;
}
var version = await client.GetStringAsync(url);
var output = JsonConvert.DeserializeObject<Version>(version);
client.Dispose();
return output;
}
You are causing a deadlock, as I explain on my blog. By default, await captures a "context" (in this case, the ASP.NET request context) and uses that to resume the async method. The ASP.NET request context only allows one thread in at a time, and you're blocking that thread by calling Result, thus preventing the async method from completing.
Your console app doesn't deadlock because it doesn't have a "context", so the async methods resume on the thread pool.
The solution is to change the calling code to use:
(await GetVersion(url)).FileVersion

Categories