I am using the TaskFactory to start new task using following code.
var task = Task.Factory.StartNew(async () =>
{
await Task.Run(() =>
{
// Do API Call
var saveResponse = doAPICall();
}).ConfigureAwait(false);
}).Unwrap();
task.Wait();
The code for doAPICall() is like below which is calling an external API which returns the Task.
private string doAPICall()
{
Task<string> response = client.FindBags(request);
response.Wait(60000);
if (response.Status == TaskStatus.RanToCompletion)
{
return response.Result;
}
}
The issue occurs in doAPICall() function that Task 'response' status never change to RanToCompletion and it is always in WaitingForActivation status. I already tried to increase the wait timeout but still no luck. I am using the TaskFactory instead of Task because of in future I want to create custom TaskFactory for more control over scheduler and concurrency.
Is that something I am missing in my code that inner task never get executed?
Edit I modified the code of calling the doAPICall() according to comment of removing unnecessary thread but still no luck. :-(
var task = Task.Factory.StartNew(() =>
{
// Do API Call
var saveResponse = doAPICall();
});
task.Wait();
You're currently using sync-over-fake-async-over-fake-async-over-sync-over-async. That is seriously messed up.
Follow these guidelines:
Task.Factory.StartNew
. Ever. I am using the TaskFactory instead of Task because of in future I want to create custom TaskFactory for more control over scheduler and concurrency.
Custom task schedulers don't work well with asynchronous code. You'll probably have to adopt more async-friendly solutions for scheduling/concurrency. More info on my blog . Wait
calls and a Result
, both of which are serious red flags. More info on my blog . Task.Status
in production code. It's OK for debugging, but you shouldn't ever have to use it for actual logic. There is always a better solution. More info on my blog . Task.Run
from the UI layer, not nested within helper/library code. In other words, use it to call methods, not implement methods. More info on my blog . Working from the innermost method out:
private async Task<string> doAPICallAsync()
{
Task<string> responseTask = client.FindBags(request);
// Note: it would be far better to use a cancellation token here instead of a "timed wait".
Task timeoutTask = Task.Delay(60000);
Task completedTask = await Task.WhenAny(responseTask, timeoutTask);
if (completedTask == responseTask)
return await completedTask;
}
and your calling code becomes:
var saveResponse = await doAPICallAsync();
You are wrapping an async call in a sync call and then in two async calls. That is way to much, just use one async call and you will be fine.
private Task<string> doAPICallAsync()
{
return client.FindBags(request);
}
If you need to do some work after client.FindBags(request)
use this version:
private async Task<string> doAPICallAsync()
{
var result = await client.FindBags(request);
var someNewResult = //do something with result
return someNewResult;
}
Then call it like this:
var result = await doAPICallAsync();
If you really need a sync version
private string doAPICall()
{
return client.FindBags(request).Result;
}
And call it like this:
var result = doAPICall();
If you can, don't forget to add ConfigureAwait(false)
after every await.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.