我讀的「C#果殼中的」異步功能部分。一個例子是如下:緩存異步函數結果在C#
假設我們需要處理「下載」按鈕,單擊事件,我們希望緩存下載結果。如果我們不在乎下載相同的網站萬一按鈕被重複點擊,那麼它是eaiser。
private static Dictionary<string, string> _cache = new Dictionary<string, string>();
async Task<string> DownloadAsync(string uri)
{
string content;
if (_cache.TryGetValue(uri, out content)) return content;
return _cache[uri] = await new WebClient().DownloadStringTaskAsync(uri);
}
但是,這意味着它會發出重複下載到同一個網站,如果,例如,它的點擊連續兩次!爲了保護這一點,本書建議緩存Task<string>
。
private static Dictionary<string, Task<string>> _futureCache = new Dictionary<string, Task<string>>();
Task<string> GetWebPage(string uri)
{
lock (_futureCache)
{
Task<string> task;
if (_futureCache.TryGetValue(uri, out task)) return task;
return _futureCache[uri] = new WebClient().DownloadStringTaskAsync(uri);
}
}
但我不明白,這種保護是如何有效。我認爲Click事件處理程序是這樣的:
_downloadBtn.Click += async (sender, args) =>
{
var uri = "http://www.bbc.co.uk"; // for argument sake, it always downloads bbc...
string result = await GetWebPage(uri);
// process the result...
};
如果由於某種原因,通過第一次點擊觸發的下載仍在進行中,然後單擊該按鈕的第二次;是不是會繼續下載頁面兩次,因爲在第二次點擊被觸發時緩存還沒有從第一次下載填充?如果我的理解錯誤,請解釋原因。否則,如何實現這樣的緩存來保護重複的用戶點擊?
順便說一句,我明白,如果它的事件處理程序(UI)方面如外使用的高速緩存有效工作在它下面只下載一次。
async void Foo()
{
var uri = "http://www.bbc.co.uk";
string result;
for (int i = 0; i < 2; i++) //Stimulate repeated call
{
result = await GetWebPage(uri);
Console.WriteLine(result.Length);
}
}
該代碼正常工作。提示:'GetWebPage'中沒有'await' :) –
@LucasTrzesniewski它故意沒有等待煽動併發! – stt106
沒錯,當已經有進行中的任務(或者,如果它已經完成了對這個問題)的代碼不會添加第二個任務:) –