2012-10-15 105 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; 
相關問題