parallel.foreach和perfmon报告了线程

时间:2012-07-10 17:28:43

标签: c# parallel-processing task perfmon

我有一个应用程序从一个包含100s-1000s行的文本文件中读取。

使用parallelOptions使用parallel.foreach处理每一行,以限制触发的任务量。这是“控制器”任务。

在这个“控制器”中,parallel.foreach是另一个执行实际工作的parallel.foreach。触发的每个控制器任务将执行相同的工作,使用原始文件行中指定的不同数据输入。同样,这项工作parallel.foreach正在使用并行选项来限制已启动的任务量。

在我上次的测试中,我用过 控制器foreach:MaxDegreeOfParallelism = 4 工人foreach:MaxDegreeOfParallelism:4

根据我的数学,应该意味着任何时候最多有16个任务在工作。

但是,当我检查perfmon.exe时,我可以看到我的应用程序使用700个线程。再过几个小时,这将超过1000个。

这怎么可能?为什么GC不收集这些完成的线程?

以前,我的代码在Thread []中触发了实际线程并遇到同样的问题。然后我把它移到了Task []并遇到了同样的问题。我假设某处存在线程泄漏,并且引用仍然指向线程/任务。我花了很多时间寻找这个无济于事。

所以我转向了parallel.foreach,并认为如果我从未创建任务的引用,那么任务泄漏就不会发生,因为这一切都发生在lamda中。

但问题仍然存在。有关为什么会这样的想法?或者这是正常的吗?

添加了下面的代码,由于所有测试并尝试调试此问题,它有点乱,尝试将其清理一下。

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

2 个答案:

答案 0 :(得分:1)

显然,问题不在于任何特定的API,因为您说线程,任务和Parallel.ForEach的问题是相同的。

不要问为什么框架没有完成它的工作(因为它是)。问一下,为什么你的代码会产生比你想象的更多的线程。没有看到更多代码,这个问题就无法得到完全解答。

答案 1 :(得分:1)

我做了一点改写。它在我的机器上只有22个线程(8个proc盒子)。随意使用任何这些变化:

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