Я новичок в асинхронном программировании на С#, и я все еще не понимаю несколько вещей. Я читал, что после .NET 4.5 APM и EAP больше не рекомендуются для новой разработки, поскольку предполагается, что TAP заменит их (источник).
Думаю, я понял, как работает async/await, и смогу использовать их для выполнения операций ввода-вывода с асинхронными методами. Например, я мог бы написать асинхронный метод, ожидающий результата GetStringAsync HttpWebClient, поскольку он объявлен как асинхронный метод. Замечательно.
Мой вопрос: что, если у нас есть операция ввода-вывода, которая происходит в методе, который не объявлен как асинхронный? Вот так: предположим, у меня есть API с методом
string GetResultFromWeb()
который запрашивает что-то из Интернета. У меня есть много разных запросов, и я должен использовать для этого этот метод. И затем мне нужно обработать каждый результат запроса. Я понимаю, что сделал бы это, если бы это был асинхронный метод:
Task<string> getResultTask = GetResultFromWeb(myUrl);
// Do whatever I need to do that doesn't need the query result
string result = await getResultTask;
Process(result);
Но так как это не так, я не могу его дождаться - он говорит мне, что строка не ожидается. Итак, мой вопрос: есть ли способ выполнять эти операции ввода-вывода асинхронно без необходимости создавать один поток для каждого запроса? Если бы я мог, я хотел бы создавать как можно меньше потоков, не блокируя ни один из потоков.
Один из способов, который я обнаружил, заключался в реализации APM, следуя этой статье. от Джеффри Рихтера, а затем в моем методе Begin я вызываю ThreadPool.QueueWorkItem(GetResultFromWeb, asyncResult). Как это:
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();
}
}
Затем я использую AsyncEnumerator и начинаю (BeginQuery) несколько запросов и обрабатываю результаты по мере их завершения (используя yield return/EndQuery). Кажется, это работает хорошо. Но, прочитав так много о том, что APM устарел, мне стало интересно, как я могу сделать это с помощью TAP. Кроме того, есть ли какие-либо проблемы с этим подходом APM?
Спасибо!