zhe*_* yu 4 c# asynchronous task
When reading
How to: Create Pre-Computed Tasks
the example method DownloadStringAsync returns
Task.Run( async ()=> { return await new WebClient().DownloadStringTaskAsync(address)})
Run Code Online (Sandbox Code Playgroud)
I wonder why we need to wrap a async method in a Task.Run()? the WebClient().DownloadStringTaskAsync() method returns a Task itself.
我认为问题在于他们想展示如何使用Task.FromResult,然后将自己打结,因为他们想使用Task返回方法。
如今编写使用Task返回方法的代码的自然方法是使它们async. 但是,如果你这样做,就会Task.FromResult消失:
// Asynchronously downloads the requested resource as a string.
public static async Task<string> DownloadStringAsync(string address)
{
// First try to retrieve the content from cache.
string content;
if (cachedDownloads.TryGetValue(address, out content))
{
return content;
}
content = await new WebClient().DownloadStringTaskAsync(address);
cachedDownloads.TryAdd(address, content);
return content;
}
Run Code Online (Sandbox Code Playgroud)
更简单的代码,仍然达到了总体目标。除非您希望cachedDownloads.TryAddCPU 占用很大,在这种情况下,他们的版本还保证将其推送到线程池中运行。
简而言之- 不要复制此代码,这不是从2开始工作的好例子。
这是避免在不需要时分配async状态机1的版本,显示Task.FromResult但仍然不使用Task.Run:
// Asynchronously downloads the requested resource as a string.
public static Task<string> DownloadStringAsync(string address)
{
// First try to retrieve the content from cache.
string content;
if (cachedDownloads.TryGetValue(address, out content))
{
return Task.FromResult(content);
}
return DownloadStringSlowAsync(address);
}
private static async Task<string> DownloadStringSlowAsync(string address)
{
string content = await new WebClient().DownloadStringTaskAsync(address);
cachedDownloads.TryAdd(address, content);
return content;
}
Run Code Online (Sandbox Code Playgroud)
更好的是:(不,这不是一个词,我不在乎)
static ConcurrentDictionary<string, Task<string>> cachedDownloads =
new ConcurrentDictionary<string, Task<string>>();
// Asynchronously downloads the requested resource as a string.
public static Task<string> DownloadStringAsync(string address)
{
// First try to retrieve the content from cache.
Task<string> content;
if (cachedDownloads.TryGetValue(address, out content))
{
return content;
}
return DownloadStringSlowAsync(address);
}
private static async Task<string> DownloadStringSlowAsync(string address)
{
string content = await new WebClient().DownloadStringTaskAsync(address);
cachedDownloads.TryAdd(address, Task.FromResult(content));
return content;
}
Run Code Online (Sandbox Code Playgroud)
因为现在我们的缓存只包含已完成的任务,我们可以一遍又一遍地分发它们,而不是Task在每个请求上重复分配新对象。
当然,这些方法中的任何一种只有在缓存对象(string此处)是不可变的情况下才真正可行。
1不要自动执行此操作。这应该是基于此类分配是否会导致性能问题的深思熟虑的决定。
2这也是缓存的一个不好的例子,因为正如 Raymond Chen 指出的那样,具有错误策略的缓存是内存泄漏的另一个名称。在这个例子中,根本没有过期。