1

数百から数千の行を含むテキスト ファイルから読み取るアプリケーションがあります。

各行は、ParallelOptions を使用して parallel.foreach を使用して処理され、実行されるタスクの量を制限します。これが「コントローラー」タスクです。

この「コントローラー」内には、実際の作業を実行する別の parallel.foreach があります。起動された各コントローラ タスクは、元のファイル行で指定された異なるデータ入力で同じ作業を実行します。この作業でも、parallel.foreach は paralleloptions を使用して、実行されるタスクの量を制限しています。

前回のテストでは、Controller foreach: MaxDegreeOfParallelism=4 を使用しました。 Worker foreach: MaxDegreeOfParallelism:4

私の計算によると、一度に最大 16 個のタスクが動作することを意味するはずです。

しかし、perfmon.exe を確認すると、アプリケーションが 700 スレッドを使用していることがわかります。さらに数時間後には 1000 を超えます。

どうすればいいの?GC がこれらの終了したスレッドを収集しないのはなぜですか?

以前、私のコードは同じ問題で Thread[] 内の実際のスレッドを起動していました。次に、それを Task[] に移動しましたが、同じ問題がありました。どこかにスレッドリークがあり、参照がまだスレッド/タスクを指していると思いました。これを探すのに何時間も費やしましたが、役に立ちませんでした。

したがって、タスクへの参照が作成されていない場合、すべてラムダ内で発生するため、タスクリークは発生しないという考えで、parallel.foreach に移行しました。

しかし、問題は解決しません。これがなぜなのかについてのアイデアはありますか?それとも正常ですか?

以下のコードを追加しました。すべてのテストが原因で少しごちゃごちゃになっており、この問題をデバッグしようとして、少しクリーンアップしようとしました。

public static void RunActions(
    List<paramsActionSettings> listActions,
    string[] arrList,
    int numThreads,
    string domain = null,
    delGetParamsActionSettings delGetActionsList = null,
    delProcessString callbackActionsComplete = null
    )
{

    int iCntr= 0;
    int iTotal = arrList.Length;


    ParallelOptions prlOptions = new ParallelOptions
    {
        MaxDegreeOfParallelism = numThreads
    };

    //foreach (string listItemIter in arrList)
    object oLock = new object();
    Parallel.ForEach(arrList, prlOptions,(listItemIter) =>
    {
        lock (oLock)
        {
            Console.WriteLine("starting "+iCntr + " of " + iTotal + " run actions");
            iCntr++;
        }

        string listItemCopySafe = string.Copy(listItemIter);

        bool bCanDo = true;
        List<paramsActionSettings> listActionsUse;
        if (listActions == null)
        {
            listActionsUse = delGetActionsList();
        }
        else
        {
            listActionsUse = listActions;
        }
        foreach (paramsActionSettings prms in listActionsUse)
        {
            if (prms.delCanDo != null && !prms.delCanDo(listItemCopySafe, domain))
            {
                bCanDo = false;
                break;
            }
        }
        if (!bCanDo) return;


        List<paramsFire> listParams = new List<paramsFire>();

        //create a list of paramsfire objects, the object holds the params and the delfunction
        foreach (paramsActionSettings prms in listActionsUse)
        {
            listParams.Add(new paramsFire(prms.delGetDoParams(listItemCopySafe), prms.delDoSomething));
        }


        FireActions(listParams, callbackActionsComplete, listItemCopySafe);
        Console.WriteLine("Finished " + iCntr + " of " + iTotal );
    }); 
}



private static void FireActions(List<paramsFire> list, delProcessString callbackActionsComplete, string itemArr)
{
    int icntr = 0;
    foreach (paramsFire prms in list)
    {
        try
        {
            if (icntr == 0) 
            {
                if (!prms.delDoSomething(prms.oParams))
                {
                    break;
                }
            }
            else
            {
                prms.delDoSomething(prms.oParams); 
            }
            icntr++;

        }
        catch (Exception e)
        {
            ErrorLog.WriteLine("foreach (paramsFire prms in list)");
            UtilException.Dump(e, "foreach (paramsFire prms in list)");
        }
    } 
     if (callbackActionsComplete != null)
    {
        try
        {
            callbackActionsComplete(itemArr);
        }
        catch { }
    }
}
4

2 に答える 2

1

明らかに、問題はスレッド、タスク、およびParallel.ForEach.

フレームワークが機能しない理由を尋ねないでください (機能しているからです)。コードが意図したよりも多くのスレッドを生成している理由を尋ねてください。これ以上のコードを確認しないと、この問題に完全に回答することはできません。

于 2012-07-10T19:11:12.527 に答える
1

少し書き直しました。私のマシン(8 procボックス)では最大22スレッドしか取得できませんでした。これらの変更を自由に採用してください。

    public static void RunActions(
        IEnumerable<paramsActionSettings> listActions,
        IEnumerable<string> arrList,
        int numThreads,
        string domain = null,
        delGetParamsActionSettings delGetActionsList = null,
        delProcessString callbackActionsComplete = null)
    {

        var cntr = 0;
        var total = arrList.Count();

        var prlOptions = new ParallelOptions
        {
            MaxDegreeOfParallelism = numThreads
        };

        ////foreach (var listItemIter in arrList)
        Parallel.ForEach(arrList, prlOptions, listItemIter =>
        {
            Interlocked.Increment(ref cntr);
            Console.WriteLine("starting " + cntr + " of " + total + " run actions");

            var listItemCopySafe = string.Copy(listItemIter);

            var listActionsUse = listActions ??
                ((delGetActionsList == null) ? new paramsActionSettings[0] : delGetActionsList());
            var canDo = listActionsUse.All(prms => prms.delCanDo == null
                || prms.delCanDo(listItemCopySafe, domain));

            if (!canDo)
            {
                return;
            }

            var listParams = listActionsUse.Select(prms => new paramsFire(
                prms.delGetDoParams(listItemCopySafe),
                prms.delDoSomething));

            // create a list of paramsfire objects, the object holds the params and the delfunction
            FireActions(listParams, callbackActionsComplete, listItemCopySafe);
            Console.WriteLine("Finished " + cntr + " of " + total);
        });
    }

    private static void FireActions(
        IEnumerable<paramsFire> list,
        delProcessString callbackActionsComplete,
        string itemArr)
    {
        var icntr = 0;

        foreach (var prms in list)
        {
            try
            {
                if (icntr == 0)
                {
                    if (!prms.delDoSomething(prms.oParams))
                    {
                        break;
                    }
                }
                else
                {
                    prms.delDoSomething(prms.oParams);
                }

                icntr++;
            }
            catch (Exception e)
            {
                ErrorLog.WriteLine("foreach (paramsFire prms in list)");
                UtilException.Dump(e, "foreach (paramsFire prms in list)");
            }
        }

        if (callbackActionsComplete == null)
        {
            return;
        }

        try
        {
            callbackActionsComplete(itemArr);
        }
        catch
        {
        }
    }
于 2012-07-11T15:34:04.440 に答える