[英]Is this running Asynchronously?
我目前有以下內容:
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
?
不知道我對此的理解是否完全正確...
BeginGetResponse
是異步的,但是它在.NET中使用了一種較舊的異步編程范例,稱為異步編程模型或(APM)。 Async-await
使用一種新的方式進行異步編程,該方法基於基於任務的異步模式 。
您可以在此處閱讀有關異步編程模式的更多信息。
有一種方法可以通過TaskFactory.FromAsync方法將支持APM的較舊API轉換為較新的API,以將您的方法轉換為async
方法。
我認為您需要這樣的東西:
myRequestState.response =
await TaskFactory.FromAsync(
request.BeginGetResponse,
request.EndGetResponse,
Tuple.Create(myRequestState, actorID));
如果使用的是.NET 4.5或更高版本,則在HttpWebRequest
對象上使用的首選方法是GetResponseAsync()
請參見此處。
因此,您的網絡通話如下所示:
//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(異步編程模型)是有問題的,因為它需要您手動配置等待和狀態等信息
TPL(任務並行庫)引入了TAP模式(基於任務的異步模式),通過將等待和狀態管理與Lambda表達式和Task
對象包裝在一起,為您清理並處理了許多繁重的Task
(第二個示例) 。
通過允許您直接await
Task
對象,可以在.NET 4.5中更進一步。 而不是需要調用Task.Result
(這可能很麻煩,因為Task
對象中發生的異常都包裝在AggregateException
對象中,您必須對其進行展開/展開以查看實際發生了什么)。
通過在TAP中使用async / await,您將再次利用該語言中內置的功能,這些功能會自動等待任務並返回結果,或者在出現異常的情況下,它會自動打開異常包裝並將其拋出給您一個普通的同步方法(它還不止於此,但是就頂級解釋而言,就是這么簡單-有關更多詳細信息,請參見此處 。)
最重要的是,它還可以使您的方法擺脫混亂,並讓您更清楚地了解方法中發生的事情-並使它更易於維護。
最后,要實際回答這個問題 -是的,使用BeginGetResponse
的動作是異步的,但是,您不能等待該調用,因為它使用了回調,而不是使對象返回等待狀態。
因此,雖然您沒有在問題中包含它,但我假設您具有DownloadBitmap
的方法簽名,如下所示: public async Task DownloadBitmap(/* args */)
但是,您沒有在該方法中等待任何東西,因為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)。
我知道我沒有在此函數中使用
await
,但是我認為在任何地方都不需要它的原因是因為BeginGetResponse
已經是異步的?
你說得對,你不需要使用async
因為你下面一個不同的模式,這也是異步的關鍵字。 具有BeginXXX
和EndXXX
的那個稱為APM(異步編程模型) 。 async-await
與稱為TAP(基於任務的異步模式)的更新模式並駕齊驅。
如果您決定使用TAP,則有一種更輕松的方法來實現您要完成的任務。
在這種情況下,根本不需要任何同步原語。 使用HttpClient
中存在的現有TAP HttpClient
代替:
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 API,而不是使用APM模式的包裝程序自己創建它們。 這樣可以節省幾行代碼,並可以減少代碼的冗長程度。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.