Reputation: 1676
How do I wrap code like below in a Task based async method?
void ExecuteThreadedAsync(Action a) {
ThreadPool.QueueUserWorkItem(x=>
{
action();
});
}
Currently, this method is called like:
void Method() {
var context = GetSomeContext();
ExecuteThreadedAsync(() =>
{
var result = TimeConsumingWebServiceCall();
context.Result = result;
});
}
But what I want is something like:
async void Method() {
var context = GetSomeContext();
await ExecuteTaskBasedAsync(() =>
{
var result = TimeConsumingWebServiceCall();
context.Result = result;
});
}
Or:
async void Method() {
var context = GetSomeContext();
var result = await ExecuteTaskBasedAsync<Result>(() =>
{
var result = TimeConsumingWebServiceCall();
return result;
});
context.Result = result;
}
Upvotes: 1
Views: 819
Reputation: 7612
It depends on what the method TimeConsumingWebServiceCall()
does - from its name, I infer that it calls a web service and time consuming
happens due to slow response from the service. This is a IO bound task. Using ThreadPool.QueueUserWorkItem
or Task.Run
to synchronously call IO bound task is generally an anti-pattern. You are just offloading work to another thread which is anyway going to synchronously block on the web service call.
Task.Run
is more suitable to offload compute bound tasks.
In your case, you should investigate how the TimeConsumingWebServiceCall
actually calls the web service and you should use asynchronous IO API's.
Generate task-based operations
while creating proxy (Add Service Reference).System.Net.WebClient
? Switch to the new System.Net.Http.HttpClient
- start using its asynchronous methods like GetStringAsync
or GetStreamAsync
.This way you can actually leverage the benefit of asynchronous API without un-necessarily blocking threads.
async Task Method() {
var context = GetSomeContext();
var result = await TimeConsumingWebServiceCallAsync();
context.Result = result;
}
async Task TimeConsumingWebServiceCallAsync() {
var httpClient = new HttpClient();
var results = await httpClient.GetStringAsync(url); // or await wcfProxy.YourWCFMethodAsync();
// do processing if necessary
return results;
}
Upvotes: 3
Reputation: 6181
This is what you can do in order to wrap a TimeConsumingWebServiceCall
so that it can be executed asynchronously
async void MethodAsync()
{
var context = GetSomeContext();
context.Result = await Task.Factory.StartNew(() =>
{
return TimeConsumingWebServiceCall();
});
}
async void Method()
{
var TimeConsumingTask = Task.Factory.StartNew(() =>
{
return TimeConsumingWebServiceCall();
});
var context = GetSomeContext();
context.Result = await TimeConsumingTask;
}
The reason behind this is to start the TimeConsumingTask
even before you invoke GetSomeContext()
as it can be executed parallely to TimeConsumingTask
.
When GetSomeContext()
finishes you await
for the TimeConsumingTask
to finish to assign it's result.
Upvotes: 0
Reputation: 28737
You can use the static Task.Run
method:
async void Method() {
var context = GetSomeContext();
await Task.Run(() =>
{
var result = TimeConsumingWebServiceCall();
context.Result = result;
});
}
or
async void Method() {
var context = GetSomeContext();
context.Result = await Task.Run(() => TimeConsumingWebServiceCall());
}
Upvotes: 0