2012-06-21 57 views
3

我有一些異步方法異步方法用foreach

public static Task<JObject> GetUser(NameValueCollection parameters) 
     { 
      return CallMethodApi("users.get", parameters, CallType.HTTPS); 
     } 

我下面寫

public static IEnumerable<JObject> GetUsers(IEnumerable<string> usersUids, Field fields) 
{ 
    foreach(string uid in usersUids) 
    { 
     var parameters = new NameValueCollection 
          { 
           {"uids", uid}, 
           {"fields", FieldsUtils.ConvertFieldsToString(fields)} 
          }; 
     yield return GetUser(parameters).Result; 
    } 
} 

法這種方法是異步的?如何使用Parallel.ForEach編寫此代碼?

回答

4

有點像這樣。

public static IEnumerable<JObject> GetUsers(IEnumerable<string> usersUids, Field fields) 
{ 
    var results = new List<JObject> 
    Parallel.ForEach(usersUids, uid => { 
     var parameters = new NameValueCollection 
          { 
           {"uids", uid}, 
           {"fields", FieldsUtils.ConvertFieldsToString(fields)} 
          }; 
     var user = GetUser(parameters).Result; 
     lock(results) 
      results.Add(user); 
    }); 
    return results; 
} 

注意:結果將不會按照您的預期相同的順序。

+0

謝謝!工作正常。 – BILL

+0

請注意,上述代碼中存在爭用條件,因爲「結果」列表正在被同時修改。不可預知的結果和失敗將隨機發生。至少你需要一個圍繞'Add'操作的鎖。 –

+0

感謝bojan ...我只是在沒有測試的情況下輸入了代碼作爲插圖......它似乎只是逐字使用。哎喲!無論如何,我固定了比賽條件 –

2

您的方法不是異步的。假設你的GetUser方法已經啓動了一個異步任務,Parallel.ForEach將使用附加的線程來啓動你的任務,這可能不是你想要的。

相反,你可能想要做的是啓動所有任務並等待它們完成:

public static IEnumerable<JObject> GetUsers(IEnumerable<string> usersUids, Field fields) 
{ 
    var tasks = usersUids.Select(
     uid => 
     { 
      var parameters = new NameValueCollection 
      { 
       {"uids", uid}, 
       {"fields", FieldsUtils.ConvertFieldsToString(fields)} 
      }; 
      return GetUser(parameters); 
     } 
    ).ToArray(); 

    Task.WaitAll(tasks); 

    var result = new JObject[tasks.Length]; 
    for (var i = 0; i < tasks.Length; ++i) 
     result[i] = tasks[i].Result; 

    return result; 
} 

如果你也想在平行的,您可以使用PLINQ來啓動他們:

var tasks = usersUids.AsParallel().AsOrdered().Select(
     uid => 
     { 
      var parameters = new NameValueCollection 
      { 
       {"uids", uid}, 
       {"fields", FieldsUtils.ConvertFieldsToString(fields)} 
      }; 
      return GetUser(parameters); 
     } 
    ).ToArray(); 

兩個代碼片段保存的UID的相對排序和返回的對象 - result[0]對應usersUids[0]