I'm new to asynchronous programming in C# and I'm still confused about a few things. I've read that after .NET 4.5, the APM and EAP are no longer recommended for new development since the TAP is supposed to replace them (source).
I think I understood how async/await works and I'd be able to use them for performing IO operations that have async methods. For example, I could write an async method that awaits for an HttpWebClient's GetStringAsync result, since it's declared as an async method. That's great.
My question is: what if we have an IO operation that happens in a method that is not declared as async? Like this: suppose I have an API that has a method
string GetResultFromWeb()
which queries something from the Web. And I have lots of different queries to do and I must use this method to do so. And then I need to process each query result. I understand that I'd do this if that was an async method:
Task<string> getResultTask = GetResultFromWeb(myUrl);
// Do whatever I need to do that doesn't need the query result
string result = await getResultTask;
Process(result);
But since it's not, I cannot await for it -- it tells me string is not awaitable. So my question is: is there any way of performing these IO operations asynchronously without having to create one thread for each query? If I could, I'd like to create as less threads as possible, without having to block any of the threads.
One way I found to do so was by implementing APM, following this article from Jeffrey Richter and then, in my Begin method, I call ThreadPool.QueueWorkItem(GetResultFromWeb, asyncResult). Like this:
public class A {
private void DoQuery(Object ar){
AsyncResult<string> asyncResult = (AsyncResult<string>) ar;
string result = GetResultFromWeb();
asyncResult.SetAsCompleted(result, false);
}
public IAsyncResult BeginQuery(AsyncCallback){
AsyncResult<string> asyncResult = new AsyncResult<string>(callback, this);
ThreadPool.QueueUserWorkItem(DoQuery, asyncResult);
return asyncResult;
}
public string EndQuery(IAsyncResult ar){
AsyncResult<string> asyncResult = (AsyncResult<string>)ar;
return asyncResult.EndInvoke();
}
}
Then I use an AsyncEnumerator and begin (BeginQuery) several queries and process the results as each one of them finishes (using yield return / EndQuery). This seems to work well. But after reading so much that APM is obsolete, I was wondering how could I do this using TAP. Also, is there any problem with this APM approach?
Thanks!