给定一个带有GetData方法的类。一些其他客户端调用GetData,而不是每次都获取数据,我想创建一个模式,其中第一个调用启动任务以获取数据,其余调用等待任务完成。
private Task<string> _data;
private async Task<string> _getdata()
{
return "my random data from the net"; //get_data_from_net()
}
public string GetData()
{
if(_data==null)
_data=_getdata();
_data.wait(); //are there not a problem here. cant wait a task that is already completed ? if(_data.status != rantocompletion) _data.wait() is not any better, it might complete between the check and the _data.wait?
return _data.Result;
}
我如何正确地进行模式?
(溶液)
private static object _servertime_lock = new object();
private static Task<string> _servertime;
private static async Task<string> servertime()
{
try
{
var thetvdb = new HttpClient();
thetvdb.Timeout = TimeSpan.FromSeconds(5);
// var st = await thetvdb.GetStreamAsync("http://www.thetvdb.com/api/Updates.php?type=none");
var response = await thetvdb.GetAsync("http://www.thetvdb.com/api/Updates.php?type=none");
response.EnsureSuccessStatusCode();
Stream stream = await response.Content.ReadAsStreamAsync();
XDocument xdoc = XDocument.Load(stream);
return xdoc.Descendants("Time").First().Value;
}
catch
{
return null;
}
}
public static async Task<string> GetServerTime()
{
lock (_servertime_lock)
{
if (_servertime == null)
_servertime = servertime();
}
var time = await _servertime;
if (time == null)
_servertime = null;
return time;
}
答案 0 :(得分:0)
两次致电Wait()
没有错;第二个电话不会做任何事情
实际上,如果任务未完成,Result
属性将隐式调用Wait()
。
作为旁注,您应该考虑使GetData()
异步,以允许调用者决定何时或是否等待。
请注意,您的代码不是线程安全的
如果可能从多个线程调用GetData()
,则应使用Lazy<T>
类。
答案 1 :(得分:0)
我想创建一个模式,第一个调用启动任务以获取数据,其余调用等待任务完成。
我建议您使用asynchronous lazy initialization,我的博客上有详细说明。 AsyncLazy<T>
类型简化了您需要编写的代码:
private readonly AsyncLazy<string> _data = new AsyncLazy<string>(async () =>
{
return "my random data from the net"; //get_data_from_net()
});
public Task<string> GetData()
{
return await _data;
}
或者,如果您的客户都是async
,您可以这样做:
public AsyncLazy<string> Data { get; private set; }
Constructor()
{
Data = new AsyncLazy<string>(async () =>
{
return "my random data from the net"; //get_data_from_net()
});
}
然后您的客户可以这样做:
var data = await my.Data;