Reputation: 685
I am using the Microsoft Web API 2.2 Client to request data from an API endpoint. After I get the data I run x number of DoSomeWork. I want to make sure the data loads first before I run the DoSomeWork functions.
Based on the code below I was expecting the following output.
"Starting GetSomething" "Done with GetSomething" "Start work# 1" "Start work# 2"
But I getthe following "Starting GetSomething" "Start work# 1" "Done with GetSomething" "Start work# 2"
static void Main()
{
try
{
Task getSomethingTask = Task.Factory.StartNew(()=>GetSomething());
getSomethingTask.Wait();
Task[] tasks = new Task[2] {
Task.Facotry.StartNew(()=>DoSomeWork(1)),
Task.Facotry.StartNew(()=>DoSomeWork(2))
};
Task.WaitAll(tasks);
}
catch(Exception ex)
{
throw ex;
}
}
static async Task GetSomething()
{
Console.WriteLine("Starting GetSomething");
try
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(SOME_URL);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/v1/somethings");
somethingList = await response.Content.ReadAsAsync<SomeObject>();
}
catch (Exception)
{
throw;
}
Console.WriteLine("Done with GetSomething");
}
static async Task DoSomeWork(int workNumber)
{
Console.Writeline("Start work#" + workNumber);
}
Upvotes: 0
Views: 191
Reputation: 457472
When doing asynchronous programming (i.e., I/O-bound), you want to avoid StartNew
, Wait
, and WaitAll
. Instead, use async
and await
for almost all logic.
Since this is a Console app, you do need a single Wait
so that the main thread doesn't exit. This should be the only Wait
in your entire app:
static void Main()
{
MainAsync().Wait();
}
static async Task MainAsync()
{
await GetSomethingAsync();
await Task.WhenAll(DoSomeWorkAsync(1), DoSomeWorkAsync(2));
}
static async Task GetSomethingAsync()
{
Console.WriteLine("Starting GetSomething");
HttpClient client = new HttpClient();
...
HttpResponseMessage response = await client.GetAsync("api/v1/somethings");
somethingList = await response.Content.ReadAsAsync<SomeObject>();
Console.WriteLine("Done with GetSomething");
}
static async Task DoSomeWorkAsync(int workNumber)
{
Console.Writeline("Start work#" + workNumber);
}
You may find my async
intro helpful.
Upvotes: 1
Reputation: 1665
When you call await
from a thread, you yield control back to its parent thread.
In this case, this is your offending line:
HttpResponseMessage response = await client.GetAsync("api/v1/somethings");
As soon as you do that, your GetSomething
thread yields control back to the Main()
thread, which is why you see your DoSomeWork
tasks executing.
If you get rid of those await
calls in GetSomething
and replace them with synchronous calls instead, you'll get the behavior that you want.
For more info, see Microsoft's async programming guide here (especially step #6 where it talks about await
): http://msdn.microsoft.com/async
Upvotes: 0
Reputation: 27022
I believe getSomethingTask
is finishing immediately because you aren't await
ing GetSomething()
.
Try this:
Task getSomethingTask = Task.Factory.StartNew(async () => await GetSomething());
or simply:
GetSomething().Wait();
Though I don't think you're really gaining anything by creating a new thread and immediately waiting for the result on the main thread.
Upvotes: 0