参考文章
请先大至看下参考文章,再回过头看案例。
下面的示例从 Web
下载字符串。 它定义了 DownloadStringAsync
方法。 此方法从 Web
异步下载字符串。 此示例还使用 ConcurrentDictionary
对象来缓存先前操作的结果。 如果此缓存中包含输入的地址,DownloadStringAsync
会使用 FromResult
方法来生成包含位于该地址的内容的 Task
对象。 否则,DownloadStringAsync
从 Web
下载文件并将结果添加到缓存中。
案例参考
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
public static class DownloadCache
{
private static readonly ConcurrentDictionary<string, string> s_cachedDownloads = new();//C#有偿Q群:927860652
private static readonly HttpClient s_httpClient = new();
public static Task<string> DownloadStringAsync(string address)
{
if (s_cachedDownloads.TryGetValue(address, out string? content))
{
return Task.FromResult(content);
}
return Task.Run(async () =>
{
content = await s_httpClient.GetStringAsync(address);
s_cachedDownloads.TryAdd(address, content);
return content;
});
}
public static async Task Main()
{
string[] urls = new[]
{
"https://learn.microsoft.com/aspnet/core",
"https://learn.microsoft.com/dotnet",
"https://learn.microsoft.com/dotnet/architecture/dapr-for-net-developers",
"https://learn.microsoft.com/dotnet/azure",
"https://learn.microsoft.com/dotnet/desktop/wpf",
"https://learn.microsoft.com/dotnet/devops/create-dotnet-github-action",
"https://learn.microsoft.com/dotnet/machine-learning",
"https://learn.microsoft.com/xamarin",
"https://dotnet.microsoft.com/",
"https://www.microsoft.com"
};
Stopwatch stopwatch = Stopwatch.StartNew();
IEnumerable<Task<string>> downloads = urls.Select(DownloadStringAsync);
static void StopAndLogElapsedTime(
int attemptNumber, Stopwatch stopwatch, Task<string[]> downloadTasks)
{
stopwatch.Stop();
int charCount = downloadTasks.Result.Sum(result => result.Length);
long elapsedMs = stopwatch.ElapsedMilliseconds;
Console.WriteLine(
$"Attempt number: {attemptNumber}\n" +
$"Retrieved characters: {charCount:#,0}\n" +
$"Elapsed retrieval time: {elapsedMs:#,0} milliseconds.\n");
}
await Task.WhenAll(downloads).ContinueWith(
downloadTasks => StopAndLogElapsedTime(1, stopwatch, downloadTasks));
// Perform the same operation a second time. The time required
// should be shorter because the results are held in the cache.
stopwatch.Restart();
downloads = urls.Select(DownloadStringAsync);
await Task.WhenAll(downloads).ContinueWith(
downloadTasks => StopAndLogElapsedTime(2, stopwatch, downloadTasks));
}
// Sample output:
// Attempt number: 1
// Retrieved characters: 754,585
// Elapsed retrieval time: 2,857 milliseconds.
// Attempt number: 2
// Retrieved characters: 754,585
// Elapsed retrieval time: 1 milliseconds.
}
该案例是在我们异步编程的时候,需要接收Task
的时候,可以使用Task.FromResult(content);
返回一个已经完成的任务,我们可以看第一次和第二次打印的结果。这样预计算的方式可以很大程度提高代码性能。