【发布时间】:2015-01-06 22:55:31
【问题描述】:
我是 C# 异步编程的新手,但我仍然对一些事情感到困惑。 我已经读到,在 .NET 4.5 之后,不再建议将 APM 和 EAP 用于新开发,因为 TAP 应该取代它们 (source)。
我想我了解 async/await 的工作原理,并且能够使用它们来执行具有异步方法的 IO 操作。例如,我可以编写一个等待 HttpWebClient 的 GetStringAsync 结果的异步方法,因为它被声明为异步方法。太好了。
我的问题是:如果我们的 IO 操作发生在未声明为异步的方法中怎么办?像这样:假设我有一个 API 有一个方法
string GetResultFromWeb()
从 Web 查询某些内容。而且我有很多不同的查询要做,我必须使用这种方法来做。然后我需要处理每个查询结果。我知道如果那是异步方法,我会这样做:
Task<string> getResultTask = GetResultFromWeb(myUrl);
// Do whatever I need to do that doesn't need the query result
string result = await getResultTask;
Process(result);
但既然不是,我不能等待它——它告诉我字符串是不可等待的。所以我的问题是:有没有什么方法可以异步执行这些 IO 操作而不必为每个查询创建一个线程?如果可以的话,我想创建尽可能少的线程,而不必阻塞任何线程。
我发现这样做的一种方法是实现 APM,遵循 Jeffrey Richter 的 this article,然后在我的 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 方法有什么问题吗?
谢谢!
【问题讨论】:
标签: c# multithreading asynchronous task