C# 在循环中创建的列表数量非常多时出现性能问题

C# 在循环中创建的列表数量非常多时出现性能问题,c#,performance,list,garbage-collection,C#,Performance,List,Garbage Collection,这是我在这里的第一篇帖子… 请考虑我是一个爱好编程的人。 症状: 我的目标是提高代码的性能。 该程序仅使用65%的CPU和500Mb内存。还有一个800Mb的可用物理内存可供程序使用,大约30%的CPU处于空闲状态。我不知道进一步利用资源和提高代码性能的瓶颈在哪里。 背景: 我写了一个程序,正在大规模测试一个金融算法。这个算法有很多参数,我试图找到最佳的参数组合。为此,我对所有可能的参数组合运行它。 该算法具有数据序列的输入。它遍历数据系列并生成结果。 为此,我将该算法的代码插入到一个Paral

这是我在这里的第一篇帖子…
请考虑我是一个爱好编程的人。 症状:
我的目标是提高代码的性能。 该程序仅使用65%的CPU和500Mb内存。还有一个800Mb的可用物理内存可供程序使用,大约30%的CPU处于空闲状态。我不知道进一步利用资源和提高代码性能的瓶颈在哪里。
背景:
我写了一个程序,正在大规模测试一个金融算法。这个算法有很多参数,我试图找到最佳的参数组合。为此,我对所有可能的参数组合运行它。
该算法具有数据序列的输入。它遍历数据系列并生成结果。
为此,我将该算法的代码插入到一个Parallel.Foreach循环中,该循环对每个参数组合运行一次。优化的关键代码是循环。
由于代码很长,我发布主干:

。。。
类candle:i可比较//数据元素,用于表示蜡烛和所有图表数据
{
公众双开;
公众双高;
…40多
}
类参数:i可比较
{
公共int par1;
公共int par2;
公共int par3;
……还有几件
}
//运行程序
{
List sourceCandleList=新列表();
列表参数列表=新列表(1000000);
//在此处填充sourceCandleList和paramList的代码
}
//编辑:启动并行处理
Parallel.ForEach(参数列表,
p=>
{
列表烛光列表=新列表(sourceCandleList.Count);
foreach(sourceCandleList中的变量cndl)
{
蜡烛c=新蜡烛();
c、 open=cndl.open;
c、 高=cndl.high;
...
//运行计算并填充烛光列表中的字段
}
//评估结果
}
paramlist大约有140.000个元素。sourceCandleList大约有2.000个元素。这意味着我会连续创建每个有2.000个项目的列表,然后在处理后删除该列表。我可以看到,在运行代码时,GC每秒清理大约200 MB内存。目前,Parallel.ForEach的1个循环需要80毫秒。该程序不会运行将任何数据存储到磁盘,而仅将数据存储到控制台。
也许有一种方法可以防止GC如此频繁地工作,那就是在内存中保留烛光列表,然后在下一个循环运行时覆盖它。为此,我需要为每个线程定义一个静态列表,但我不确定这是怎么可能的。也许只需创建一组列表,然后在新线程启动时尝试使用TryEnter捕获一个空闲列表?

编辑
我没有明确说明程序首先生成了两个列表:sourceCandleList和paramList。完成后,这些列表将不再更改。在这两个列表完全填充后,程序开始测试算法:sourceCandleList是输入,paramList中的一条记录是要应用的参数集。问题是程序每次都会定义一个新的烛光列表。因此,我需要如下内容:

ConcurrentQueue<List<candle>> ListOfCanldes = new ConcurrentQueue<List<candle>>();
ConcurrentQueue ListofCandles=新的ConcurrentQueue();
但是,我无法理解正确的语法。

问题:
为什么CPU和内存都没有得到充分利用?我是否达到了内存的最大读/写速度!?
如何避免GC减慢程序?
我怎么知道我因为GC而实际损失了多少时间
如何提高性能?

为什么CPU和内存都没有得到充分利用?我是否达到了内存的最大读/写速度

  • 没有足够的信息。但是使用
    Parallel.ForEach
    将限制您正在使用的线程数。可能不使用列表,而是使用类似
    ConcurrentQueue
    ConcurrentStack
    的内容
我会这样做,以更快地处理它们:

class Program
    {
        static ConcurrentQueue<candle> sourceCandleList = new ConcurrentQueue<candle>();
        static ConcurrentBag<param> paramList = new ConcurrentBag<param>();
        static void Main(string[] args)
        {
            var threads = new List<Thread>();
            var numberOfThreads = 10;
            for (int i = 0; i < numberOfThreads; i++)
            {
                threads.Add(new Thread(Run));
            }
            threads.ForEach(i => i.Start());
        }
        static void Run()
        {
            candle item;
            while (sourceCandleList.TryDequeue(out item))
            {
                //do you processing here
            }
        }
    }
类程序
{
静态ConcurrentQueue sourceCandleList=新ConcurrentQueue();
静态ConcurrentBag参数列表=新ConcurrentBag();
静态void Main(字符串[]参数)
{
var threads=newlist();
var numberOfThreads=10;
for(int i=0;ii.Start());
}
静态无效运行()
{
蜡烛;
while(sourceCandleList.TryDequeue(out项))
{
//你在这里加工吗
}
}
}
如何避免GC减慢程序?:不要担心GC。

我怎么能知道我因为GC而浪费了多少时间? 您可以使用VS 2015的评测,或者下载Ant Profiler之类的工具,但不要再担心GC了


如何提高性能?请参阅上面的代码剪贴。我不知道您的程序还在做什么。

最后我用以下代码解决了问题。原因是我不能让多个线程在同一队列上工作,因为我需要保持顺序或元素。在这种情况下,不需要额外的order by。
结果是,内存使用量减少了50%,并且在程序运行时变化很小。现在程序在100%上运行所有内核

static void Main(string[] args)
    {
        // Parameters to test
        List<candle> paramList = new List<candle>();

        // Original list
        List<candle> sourceList = new List<candle>();

        // Create a copy for each thread
        int maxThreads = 16;
        ConcurrentBag<int> pool = new ConcurrentBag<int>();
        List<candle>[] processList = new List<candle>[maxThreads];
        for (int i = 0; i <= maxThreads - 1; i++)
        {
            pool.Add(i);
            processList[i] = sourceList.ConvertAll(p => p);
        }
        Parallel.For(0, paramList.Count,
        new ParallelOptions { MaxDegreeOfParallelism = maxThreads },
        p =>
        {
            int slot = 0;
            int item;
            for (int i = 0; i <= 2; i++)
            {
                if (pool.TryTake(out item))
                {
                    slot = item;
                    break;
                }
                else
                {
                    i = 0;
                }
            }
            lock (processList[slot])
            {
                // Do processing here
            }
            pool.Add(slot);
        });
    }
static void Main(字符串[]args)
{
//测试参数
List paramList=新列表();
//原始列表
List sourceList=新列表();
//为每个线程创建一个副本
int-maxThreads=16;
ConcurrentBag池=新ConcurrentBag();
列表[]进程列表=新列表[maxThreads];
对于(int i=0;i p);
}
Parallel.For(0,paramList.Count,
新的并行选项{MaxDegr
static void Main(string[] args)
    {
        // Parameters to test
        List<candle> paramList = new List<candle>();

        // Original list
        List<candle> sourceList = new List<candle>();

        // Create a copy for each thread
        int maxThreads = 16;
        ConcurrentBag<int> pool = new ConcurrentBag<int>();
        List<candle>[] processList = new List<candle>[maxThreads];
        for (int i = 0; i <= maxThreads - 1; i++)
        {
            pool.Add(i);
            processList[i] = sourceList.ConvertAll(p => p);
        }
        Parallel.For(0, paramList.Count,
        new ParallelOptions { MaxDegreeOfParallelism = maxThreads },
        p =>
        {
            int slot = 0;
            int item;
            for (int i = 0; i <= 2; i++)
            {
                if (pool.TryTake(out item))
                {
                    slot = item;
                    break;
                }
                else
                {
                    i = 0;
                }
            }
            lock (processList[slot])
            {
                // Do processing here
            }
            pool.Add(slot);
        });
    }