2012-10-15 76 views
0

给定一个包含GetData方法的类。其他几个客户端调用GetData,而不是每次都获取数据,我想创建一个模式,第一个调用开始任务以获取数据,其余的调用等待任务完成。.net async/async异步数据获取方法的正确模式

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

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

作为便笺,您应该考虑制作GetData()异步以允许呼叫者决定何时或是否等待。

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

+0

我正在使用锁定if(_data == null) _data = _getdata(); - 这足够吗?或者你可以举一个懒惰班的例子。 (不熟悉它)。 –

+0

锁已足够,但速度很慢。 http://msdn.microsoft.com/en-us/library/dd642331.aspx – SLaks

+0

将我的解决方案更改为使用Lazy 很容易吗? –

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; 
相关问题