3

我有一些异步方法

 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

2 回答 2

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;
}

注意:结果的顺序与您预期的不同。

于 2012-06-21T21:17:59.450 回答
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]等。

于 2012-06-21T23:56:47.443 回答