【问题标题】:Is it possible to have a method using Parallel tasks and returns IEnumerable<T>是否可以有一个使用并行任务的方法并返回 IEnumerable<T>
【发布时间】:2011-11-24 09:30:40
【问题描述】:

我希望该方法并行执行任务,并在任务完成后“返回”结果。有没有可能有这样的东西:

   public IEnumerable<string> GetAllLogs()
   {
     var computers = GetComputers()
                            .Where(cpt => cpt.IsOnline);

     Parallel.ForEach(computers, c => c.GetLogs());

     // How to 'yield return' ?
   }

谢谢!!!

编辑:

也许我之前的示例不够明确,这里有一个新的(我希望)更明确的 ;-)

我想知道如何并行化 GetAllLogs 方法:

public class ComputerManager
{
    public IEnumerable<string> GetAllLogs(IEnumerable<IComputer> computers)
    {
        foreach (var cpt in computers)
        {
            // How to Parallelize the foreach bloc and 
            // use a 'yield return' to keep the IEnumerable<string> return type ?
            foreach (var log in cpt.GetLogs())
            {
                yield return log;
            }
        }
    }
}

    static void Main(string[] args)
    {
        ComputerManager cm = new ComputerManager();
        IComputer[] computers = new IComputer[] {new Computer(), new Computer2(), new Computer3(), new Computer4() };

        Stopwatch sw = new Stopwatch();
        sw.Start();

        foreach (string s in cm.GetAllLogs(computers))
        {
            Console.WriteLine(s);
        }

        sw.Stop();
        Console.WriteLine("Terminé en : {0}" , sw.ElapsedMilliseconds);
        Console.Read();
    }
}

public interface IComputer
{
    IEnumerable<string> GetLogs();
}


public class Computer : IComputer
{
    public IEnumerable<string> GetLogs()
    {
        string[] alphabet = new string[] { "a", "b", "c", "d", "e"};

        foreach (var letter in alphabet)
        {
            Thread.Sleep(1000);
            yield return letter;
        }
    }
}

public class Computer2 : IComputer
{
    public IEnumerable<string> GetLogs()
    {
        string[] figures = new string[] { "1", "2", "3", "4", "5" };

        foreach (var figure in figures)
        {
            Thread.Sleep(1000);
            yield return figure;
        }
    }
}


public class Computer3 : IComputer
{
    public IEnumerable<string> GetLogs()
    {
        string[] greekAlphabet = new string[] { "alpha", "beta", "gamma", "delta", "epsilon" };

        foreach (var letter in greekAlphabet)
        {
            Thread.Sleep(1000);
            yield return letter;
        }
    }
}


public class Computer4 : IComputer
{
    public IEnumerable<string> GetLogs()
    {
        string[] romanFigures = new string[] { "I", "II", "III", "IV", "V" };

        foreach (var s in romanFigures)
        {
            Thread.Sleep(1000);
            yield return s;
        }
    }
}

【问题讨论】:

  • yield “任务完成时”或“任务完成时”?

标签: c# task-parallel-library


【解决方案1】:

Reed Copsey(来自 SO 的用户)在 MSDN 论坛上发布了此内容。这可能会有所帮助!

http://social.msdn.microsoft.com/Forums/en-AU/parallelextensions/thread/3352a322-af6f-4105-b25c-9978bd85f162

// In your source, you use yield
public ClassImplementingIEnumerable: IEnumerable<int>
{
 public IEnumerable<int> GetSource()
 {
       for (int i=0;i<1000;++i)
           yield return i;
 }
}


public class ParallelProcessingConsumer {

public void SomeMethod(ClassImplementingIEnumerable sourceProvider)
{

      Parallel.ForEach(sourceProvider.GetSource(), parallelOptions, (i, loopState) => 
      {  
         // Do work in parallel!
      });
}

【讨论】:

  • 谢谢。但我希望 SomeMethod 返回 IEnumerable 这是 ClassImplementingIEnumerable.GetSource 的结果
【解决方案2】:

如果您想在并行执行开始后立即返回:

public class ComputerManager
{
    public IEnumerable<string> GetAllLogs(IEnumerable<IComputer> computers)
    {
        return computers.AsParallel().SelectMany(c => c.GetLogs());
    }
}

如果要在并行执行完成后返回:

public class ComputerManager
{
    public IEnumerable<string> GetAllLogs(IEnumerable<IComputer> computers)
    {
        return computers.AsParallel().SelectMany(c => c.GetLogs()).ToArray();
    }
}

【讨论】:

    【解决方案3】:

    这对我有用:

    • 在 Parallel.Foreach 的任务中 ConcurrentQueue 中的项目 转化为处理。
    • 任务有一个继续标记 该任务结束的标志。
    • 与任务在同一线程执行 结束一段时间出队并产生

    对我来说快速而出色的结果:

    Task.Factory.StartNew (() =>
    {
        Parallel.ForEach<string> (TextHelper.ReadLines(FileName), ProcessHelper.DefaultParallelOptions,
        (string currentLine) =>
        {
            // Read line, validate and enqeue to an instance of FileLineData (custom class)
        });
    }).
    ContinueWith 
    (
        ic => isCompleted = true 
    );
    
    
    while (!isCompleted || qlines.Count > 0)
    {
        if (qlines.TryDequeue (out returnLine))
        {
            yield return returnLine;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2010-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-28
      • 2010-09-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多