我目前有以下内容:
var tasks = new List<Task>();
foreach (myObject obj in myObjectList)
{
tasks.Add(downloadBitmap(obj.profilePath, obj.id));
}
await Task.WhenAll(tasks);
downloadBitmap
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
RequestState myRequestState = new RequestState();
myRequestState.request = request;
// Start the asynchronous request.
IAsyncResult result = request.BeginGetResponse(new AsyncCallback(RespCallback), Tuple.Create(myRequestState, actorID));
// this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, DefaultTimeout, true);
// The response came in the allowed time. The work processing will happen in the
// callback function.
allDone.WaitOne();
RespCallBack
Tuple<RequestState, int> state = (Tuple<RequestState, int>)asynchronousResult.AsyncState;
RequestState myRequestState = state.Item1;
int actorID = state.Item2;
try
{
HttpWebRequest myHttpWebRequest = myRequestState.request;
myRequestState.response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(asynchronousResult);
// Read the response into a Stream object.
Stream responseStream = myRequestState.response.GetResponseStream();
myRequestState.streamResponse = responseStream;
Bitmap bitmap = new Bitmap(responseStream);
// Do some work here
}
catch (WebException e)
{
Console.WriteLine("\nRespCallback Exception raised!");
Console.WriteLine("\nMessage:{0}", e.Message);
Console.WriteLine("\nStatus:{0}", e.Status);
}
finally
{
// Release the HttpWebResponse resource.
myRequestState.response.Close();
}
allDone.Set();
我从MSDN
网站获得了大部分内容。我也收到了警告:
This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
表示DownloadBitmap
功能。
我知道我在这个函数中没有使用await
,但我之所以认为没有必要,因为BeginGetResponse
已经asynchronous
了?
不确定我对此的理解是否完全正确......
答案 0 :(得分:1)
BeginGetResponse
是异步的,但它在.NET中使用较旧的异步编程范例,称为Asynchronous Programming Model或(APM)。 Async-await
使用基于Task Based Asynchronous Pattern的更新的异步编程方式。
您可以阅读有关asynchronus编程模式here的更多信息。
有一种方法可以通过TaskFactory.FromAsync方法将支持APM的较旧API转换为较新的API,以将您的方法转换为async
方法。
我认为你需要这样的东西:
myRequestState.response =
await TaskFactory.FromAsync(
request.BeginGetResponse,
request.EndGetResponse,
Tuple.Create(myRequestState, actorID));
答案 1 :(得分:0)
如果您使用的是.NET 4.5或更高版本,则HttpWebRequest
对象上使用的首选方法是GetResponseAsync()
,请参阅here
所以你的网络电话看起来像这样:
//note the use of the async/await
public async Task<Bitmap> DownloadBitmap(/* whatever your params were */)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
//add the rest of the data/params or anything else you need then...
// await the asynchronous request.
HttpWebResponse result = (HttpWebResponse)(await request.GetResponseAsync());
Stream responseStream = myWebResponse.GetResponseStream();
return new Bitmap(responseStream);
}
并将其称为:
var bitmaps = new List<Bitmap>();
foreach (myObject obj in myObjectList)
{
bitmaps.Add(await DownloadBitmap(obj.profilePath, obj.id));
}
如果你不想等待,你可以这样做(或者对于.NET 4.0 +):
//note the use of the the slightly older ContinueWith
public Task<Bitmap> DownloadBitmap(/* whatever your params were */)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
//add the rest of the data/params or anything else you need then...
// await the asynchronous request.
return request.GetResponseAsync().ContinueWith((antecedent) => {
HttpWebResponse myWebResponse = (HttpWebResponse)antencedent.Result;
Stream responseStream = myWebResponse.GetResponseStream();
return new Bitmap(responseStream);
});
}
并将其称为:
var tasks = new List<Task>();
foreach (myObject obj in myObjectList)
{
tasks.Add(DownloadBitmap(obj.profilePath, obj.id));
}
await tasks.WhenAll();
但这不是你要问的问题,你问的是一个异步与否的方法,使用IAsyncCallbacks
和IAsyncResults
的APM(异步编程模型)是有问题的,因为它需要您可以手动配置等待和状态等source
TPL(任务并行库)引入了TAP模式(基于任务的异步模式),通过使用Lambda表达式和{{1}包装等待和状态管理来清理并处理大量繁重工作。对象(我的第二个例子)。
通过允许您直接Task
await
对象,可以在.NET 4.5中更进一步。而不是需要调用Task
(这可能很麻烦,因为Task.Result
对象中发生的异常包含在Task
对象中,您需要解包/展平以查看实际发生的情况)。
通过在TAP中使用async / await,您再次利用语言中内置的功能自动等待任务,并返回结果,或者在异常的情况下,它会自动解包异常并抛出异常你喜欢普通的同步方法。(除此之外还有更多内容,但就顶级解释而言,就是这么简单 - 有关详细信息,请参阅here。)
最重要的是,它会使您的方法更加混乱,并且可以让您更清楚地了解方法中的内容 - 并使其更易于维护。
最后,实际回答问题 - 是的,使用的行为
AggregateException
是异步,但是,它不是一个可以等待的调用,因为它使用回调,而不是将对象返回到等待。
所以,虽然你没有在你的问题中包含它,但我假设你有BeginGetResponse
的方法签名,如此:DownloadBitmap
但是,你不是在等待那个方法中的任何东西,因为APM模式没有直接暴露句柄等待。
如果你想等待任务(这些天是.NET的首选方法),请考虑使用不同的异步模式。
来自MSDN:
异步编程模型(APM)模式(也称为IAsyncResult模式),其中异步操作需要Begin和End方法(例如,BeginWrite和EndWrite用于异步写入操作)。这种模式不再推荐用于新开发。有关更多信息,请参阅异步编程模型(APM)。
基于事件的异步模式(EAP),它需要具有Async后缀的方法,并且还需要一个或多个事件,事件处理程序委托类型和EventArg派生类型。 EAP是在.NET Framework 2.0中引入的。它不再被推荐用于新开发。有关更多信息,请参阅基于事件的异步模式(EAP)。
基于任务的异步模式(TAP),它使用单个方法来表示异步操作的启动和完成。 TAP是在.NET Framework 4中引入的,是.NET Framework中异步编程的推荐方法。 C#中的async和await关键字以及Visual Basic语言中的Async和Await运算符为TAP添加了语言支持。有关更多信息,请参阅基于任务的异步模式(TAP)。
答案 2 :(得分:0)
我知道我在这个函数中没有使用
await
但是原因 我认为没有必要在任何地方因为BeginGetResponse
已异步?
你是对的,你不需要使用async
关键字,因为你正在遵循一个同步的不同的模式。 BeginXXX
和EndXXX
的人称为APM (Asynchronous Programming Model)。 async-await
与更新的模式(TAP (Task-based Asynchronous Pattern))齐头并进。
如果您决定使用TAP,可以更轻松地实现您的目标。
在这种情况下根本不需要任何同步原语。使用HttpClient
中存在的现有TAP apis代替:
public async Task<Bitmap> DownloadBitmapAsync(string uri)
{
var httpClient = new HttpClient();
var response = await httpClient.GetAsync(uri);
using (var responseStream = await response.Content.ReadAsStreamAsync())
{
return new Bitmap(responseStream);
}
}
然后同时执行它们:
var bitmapDownloadTasks = myObjectList.Select(obj =>
DownloadBitmapAsync(obj.profilePath));
await Task.WhenAll(bitmapDownloadTasks);
注意我删除了其中一个参数,因为我看不到downloadBitmap
方法的方法签名。
这样,您就可以利用现有的TAP apis而不是使用APM模式的包装器自己创建它们。这可以为您节省几行代码,并且可以减少代码的冗长程度。