0

给定一个具有 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;

    }
4

2 回答 2

0

Wait()两次调用没有错;第二个电话不会做任何事情。
实际上,如果任务未完成,该Result属性将隐式调用。Wait()

作为旁注,您还应该考虑进行GetData()异步,以允许调用者决定何时或是否等待。

请注意,您的代码不是线程安全的。
如果GetData()可能从多个线程调用,则应使用Lazy<T>该类。

于 2012-10-15T02:44:00.597 回答
0

我想创建一个模式,其中第一个调用启动任务以获取数据,其余调用等待任务完成。

我建议您使用异步延迟初始化,如我的博客所述。该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;
于 2012-10-15T15:09:58.477 回答