使用Ienumerable.TakeWhile但只返回一组结果

时间:2014-05-18 20:56:45

标签: c# multithreading

首先,如果我的代码不好或我的描述很差,我想道歉。这是我第一次使用C#线程/任务。我在我的代码中尝试做的是查看列表中的名称和列表中的每个50个名称,启动一个新任务并将这50个名称传递给另一个将执行计算重量级方法的方法。数据。我的代码仅适用于列表中的前50个名称,并且每隔一段时间返回0个结果,我似乎无法弄清楚原因。

public static async void startInitialDownload(string value)
    {
        IEnumerable<string> names = await Helper.getNames(value, 0);
        decimal multiple = names.Count() / 50;
        string[] results;
        int num1 = 0;
        int num2 = 0;

        for (int i = 0; i < multiple + 1; i++)
        {
            num1 = i * 50;
            num2 = (50 * (i + 1));
            results = names.TakeWhile((name, index) => index >= num1 && index < num2).ToArray();
            Task current = Task.Factory.StartNew(() => getCurrentData(results));
            await current.ConfigureAwait(false);
        }
    }

4 个答案:

答案 0 :(得分:2)

将可枚举实现到一个列表中,以便计算一次,而不是循环中的每次迭代。您可以使用SkipTake方法获取列表范围:

public static async void startInitialDownload(string value) {
  IEnumerable<string> names = await Helper.getNames(value, 0);
  List<string> nameList = names.ToList();
  for (int i = 0; i < nameList.Count; i += 50) {
    string[] results = nameList.Skip(i).Take(50).ToArray();
    Task current = Task.Factory.StartNew(() => getCurrentData(results));
    await current.ConfigureAwait(false);
  }
}

或者您可以将项目添加到列表中,并在其大小合适时执行:

public static async void startInitialDownload(string value) {
  IEnumerable<string> names = await Helper.getNames(value, 0);
  List<string> buffer = new List<string>();
  foreach (string s in names) {
    buffer.Add(s);
    if (buffer.Count == 50) {
      Task current = Task.Factory.StartNew(() => getCurrentData(buffer.ToArray()));
      await current.ConfigureAwait(false);
      buffer = new List<string>();
    }
  }
  if (buffer.Count > 0) {
    Task current = Task.Factory.StartNew(() => getCurrentData(buffer.ToArray()));
    await current.ConfigureAwait(false);
  }
}

答案 1 :(得分:0)

名称TakeWhile表示只在条件为真时才接受条目。因此,如果它通过读取条件为假的条目开始,则它永远不需要任何东西。

因此,第一个循环,您从num1 = 0开始。因此,它会从num1num2读取条目。

第二个循环,你开始时num1为51.所以它再次开始阅读......并且它命中的第一个条目,条件为假,所以它会停止。

您可以尝试使用Where,或者先使用Skip

tl; dr;它:我不认为你的问题与并行任务有任何关系,我认为这是由于使用了错误的LINQ方法来提取你想要使用的名称。

答案 2 :(得分:0)

正如我从Stephen Cleary对类似(但不完全相同)问题的回答中所理解的那样,你不需要在那里使用ConfigureAwait()。

以下是相关链接:on stack overflow

这就是我要做的事情而不是你的for循环的最后两行:

Task.Factory.StartNew(() => getCurrentData(results));

那就是它。通过使用工厂,并且不等待,您将让该任务独立运行(可能在新线程上)。如果您的存储都是线程安全的(请参阅:System.Collections.Concurrent btw),那么您应该全部设置。

警告:如果你没有向我们展示之后的,那么你的结果可能会有所不同。

答案 3 :(得分:0)

它不是一个直接的解决方案,但可能会有效。

public static IEnumerable<T[]> MakeBuckets<T>(IEnumerable<T> source, int maxSize)

    {
        List<T> currentBucket = new List<T>(maxSize);

        foreach (var s in source)
        {
            currentBucket.Add(s);
            if (currentBucket.Count >= maxSize)
            {
                yield return currentBucket.ToArray();
                currentBucket = new List<T>(maxSize);

            }

        }
        if(currentBucket.Any())
            yield return currentBucket.ToArray();
    }

稍后您可以遍历MakeBucket函数的结果。