【发布时间】:2021-05-15 06:43:07
【问题描述】:
假设以下代码
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
Lazy<TimeSpan> lm = new Lazy<TimeSpan>(GetDataAsync1, System.Threading.LazyThreadSafetyMode.PublicationOnly);
return new string[] { "value1", "value2", lm.Value.ToString() };
}
private TimeSpan GetDataAsync1()
{
return GetTS().ConfigureAwait(false).GetAwaiter().GetResult();
}
// I Cant change this method, and what is inside it...
private async Task<TimeSpan> GetTS()
{
var sw = Stopwatch.StartNew();
using (var client = new HttpClient())
{
var result = await client.GetAsync("https://www.google.com/");
}
sw.Stop();
return sw.Elapsed;
}
}
关键是我正在从远程服务器获取一些数据,并希望将其缓存以备后用。由于远程服务器可能在给定点失败,我不想缓存异常,但只有成功结果......所以保持而不是等待值对我不起作用
// Cant use this, because this caches failed exception as well
Lazy<Task...> lz = ...
await lz.Value
但上面剪断了,正如预期的那样会产生死锁,因为我无法更改 GetTS,是否可以强制 Lazy 使用我的逻辑工作?
【问题讨论】:
-
如果在获取一个缓存值时没有缓存值,并且您尝试从服务器获取一个但失败了,您想做什么?你应该返回什么?
-
这个 GetTS().ConfigureAwait(false).GetAwaiter().GetResult() 叫死锁!
-
失败时,我想返回异常,并在下一个请求时重试... LazyThreadSafetyMode.PublicationOnly - 没有异步提供了开箱即用的功能...
-
@Nick,我明白了,如果我将 ConfigureAwait 移到 GetTS 中,它会解决问题...但我不能...
-
您可能会觉得这很有趣:Enforce an async method to be called once。它包括一个不使用
Lazy<T>类的实现。
标签: c# asp.net-mvc async-await task-parallel-library