32

このような並列ループを使用して何かを処理したい:

public void FillLogs(IEnumerable<IComputer> computers)
{
    Parallel.ForEach(computers, cpt=>
    {
        cpt.Logs = cpt.GetRawLogs().ToList();
    });

}

わかりました、うまくいきます。しかし、 FillLogs メソッドが IEnumerable を返すようにするにはどうすればよいですか?

public IEnumerable<IComputer> FillLogs(IEnumerable<IComputer> computers)
{
    Parallel.ForEach(computers, cpt=>
    {
        cpt.Logs = cpt.GetRawLogs().ToList();
        yield return cpt // KO, don't work
    });

}

編集

それは不可能のようです...しかし、私は次のようなものを使用します:

public IEnumerable<IComputer> FillLogs(IEnumerable<IComputer> computers)
{
    return computers.AsParallel().Select(cpt => cpt);
}

しかし、私がcpt.Logs = cpt.GetRawLogs().ToList();命令を置く場所

4

5 に答える 5

16

短いバージョン - いいえ、イテレータ ブロックでは不可能です。より長いバージョンでは、呼び出し元のイテレータ スレッド (デキューを実行) と並列ワーカー (エンキューを実行) との間で同期キュー/デキューが行われる可能性があります。ただし、補足として、ログは通常 IO バウンドであり、IO バウンドのものを並列化するとうまく機能しないことがよくあります。

呼び出し元がそれぞれを消費するのに時間がかかる場合は、一度に 1 つのログのみを処理するアプローチにメリットがあるかもしれませんが、呼び出し元が前のログを消費している間にそれを行うことができます。つまり、 の前に次のアイテムの を開始し、 ... の後に完了を待ちますが、これもかなり複雑です。簡単な例として:Task yieldyield

static void Main()
{
    foreach(string s in Get())
    {
        Console.WriteLine(s);
    }
}

static IEnumerable<string> Get() {
    var source = new[] {1, 2, 3, 4, 5};
    Task<string> outstandingItem = null;
    Func<object, string> transform = x => ProcessItem((int) x);
    foreach(var item in source)
    {
        var tmp = outstandingItem;

        // note: passed in as "state", not captured, so not a foreach/capture bug
        outstandingItem = new Task<string>(transform, item);
        outstandingItem.Start();

        if (tmp != null) yield return tmp.Result;
    }
    if (outstandingItem != null) yield return outstandingItem.Result;
}
static string ProcessItem(int i)
{
    return i.ToString();
}
于 2011-12-07T09:29:17.970 に答える
5

攻撃的にはなりたくないのですが、理解が足りないのかもしれません。Parallel.ForEachこれは、TPL が複数のスレッドで使用可能なハードウェアに従って foreach を実行することを意味します。しかし、それは、ii がその作業を並行して実行できることを意味します。yield returnリストからいくつかの値を取得し (または何でも)、必要に応じて 1 つずつ返す機会を提供します。最初に条件に一致するすべてのアイテムを見つけてから、それらを反復処理する必要がなくなります。これは確かにパフォーマンス上の利点ですが、並行して行うことはできません。

于 2011-12-07T09:28:39.303 に答える