运行VS2010的.NET内存分配分析需要很长时间才能完成.
该程序本身运行约3分钟,并产生35GB的内存分配.探查器的输出文件大约为28GB.报告分析过程花了三个多小时(在具有8GB RAM的双Xeon上)完成.
每次我运行内存分析器时都会发生这种情况.
这是您使用此工具的经历吗?
有什么办法可以加快这个过程吗?
谢谢!
我有一个程序有很多独立的计算,所以我决定并行化它.
我使用Parallel.For/Each.
双核机器的结果还可以 - 大多数时候CPU利用率约为80%-90%.但是,使用双Xeon机器(即8个内核),我只获得了大约30%-40%的CPU利用率,尽管该程序在并行部分上花费了相当多的时间(有时超过10秒),我看到它使用了与串行部分相比,这些部分中大约有20-30个线程.每个线程需要1秒以上才能完成,所以我认为它们没有理由不能并行工作 - 除非存在同步问题.
我使用了VS2010的内置分析器,结果很奇怪.即使我只在一个地方使用锁,分析器报告大约85%的程序时间用于同步(也是5-7%睡眠,5-7%执行,低于1%IO).
锁定的代码只是一个缓存(字典)get/add:
bool esn_found;
lock (lock_load_esn)
esn_found = cache.TryGetValue(st, out esn);
if(!esn_found)
{
esn = pData.esa_inv_idx.esa[term_idx];
esn.populate(pData.esa_inv_idx.datafile);
lock (lock_load_esn)
{
if (!cache.ContainsKey(st))
cache.Add(st, esn);
}
}
Run Code Online (Sandbox Code Playgroud)
lock_load_esn是Object类型的静态成员.
esn.populate使用单独的StreamReader为每个线程从文件中读取.
但是,当我按下同步按钮以查看导致最大延迟的原因时,我看到探查器报告的是作为功能入口线的线,并且不报告锁定的部分本身.
它甚至没有报告包含上述代码的功能(提醒 - 程序中唯一的锁定)作为阻塞配置文件的一部分,噪声级别为2%.当噪音水平为0%时,它会报告程序的所有功能,我不明白为什么它们被视为阻塞同步.
所以我的问题是 - 这里发生了什么?
85%的时间花在同步上怎么样?
如何找出程序中并行部分的实际问题?
谢谢.
更新:深入研究线程(使用极其有用的可视化工具)后,我发现大部分同步时间都花在等待GC线程完成内存分配上,并且由于通用数据结构调整大小操作需要频繁的分配.
我将不得不看看如何初始化我的数据结构,以便它们在初始化时分配足够的内存,可能避免GC线程的这种竞争.
我今天晚些时候会报告结果.
更新:看起来内存分配确实是问题的原因.当我在并行执行的类中使用所有词典和列表的初始容量时,同步问题更小.我现在只有大约80%的同步时间,CPU利用率达到70%(先前的峰值仅为40%左右).
我进一步钻进每个线程,发现现在很多调用GC分配用于分配不属于大字典的小对象.
我通过为每个线程提供一个预先分配的这类对象池来解决这个问题,我使用它而不是调用"new"函数.
所以我基本上为每个线程实现了一个单独的内存池,但是以非常粗糙的方式,这非常耗时,实际上并不是很好 - 我仍然需要使用很多新的来初始化这些对象,只有现在我全局执行一次,即使不得不增加池的大小,GC线程上的争用也会减少.
但这绝对不是我喜欢的解决方案,因为它不容易推广,我不想写自己的内存管理器.
有没有办法告诉.NET为每个线程分配预定义的内存量,然后从本地池中获取所有内存分配?
我有一个二进制类数据集(0/1),向"0"类倾斜很大(大约30000对1500).每个实例有7个功能,没有缺失值.
当我使用J48或任何其他树分类器时,我几乎将所有"1"实例错误分类为"0".
将分类器设置为"未分级",将每个叶子的最小实例数设置为1,将置信因子设置为1,添加具有实例ID号的虚拟属性 - 所有这些都无济于事.
我只是无法创建一个过度拟合数据的模型!
我也尝试了几乎所有Weka提供的其他分类器,但得到了类似的结果.
使用IB1获得100%的准确度(列车集上的列车集),因此不存在具有相同特征值和不同类别的多个实例的问题.
如何创建完全未修剪的树?或者强迫Weka过度填充我的数据?
谢谢.
更新:好的,这很荒谬.我只使用了大约3100个负面例子和1200个正面例子,这是我得到的树(未修剪!):
J48 unpruned tree
------------------
F <= 0.90747: 1 (201.0/54.0)
F > 0.90747: 0 (4153.0/1062.0)
Run Code Online (Sandbox Code Playgroud)
不用说,IB1仍然提供100%的精度.
更新2:不知道我是如何错过它的 - 未经训练的SimpleCart工作并且在火车上提供100%准确度的训练; 修剪过的SimpleCart并不像J48那样有偏见,并且具有不错的误报率和负面比率.
我正在尝试计算两个非常稀疏的关联数组的点积.数组包含ID和值,因此只应对两个数组共有的ID进行计算,例如
[(1, 0.5), (3, 0.7), (12, 1.3)] * [(2, 0.4), (3, 2.3), (12, 4.7)] = (0.7 * 2.3) + (1.3 * 4.7)
Run Code Online (Sandbox Code Playgroud)
我的实现(称之为dict)目前使用Dictionaries,但它的速度太慢了.
double dot_product(IDictionary<int, double> arr1, IDictionary<int, double> arr2)
{
double res = 0;
double val2;
foreach (KeyValuePair<int, double> p in arr1)
if (arr2.TryGetValue(p.Key, out val2))
res += p.Value * val2;
return res;
}
Run Code Online (Sandbox Code Playgroud)
完整数组每个都有大约500,000个条目,而稀疏数组每个只有几十到几百个条目.
我做了一些玩具版点产品的实验.首先,我试图将两个双阵列相乘,看看我能得到的最终速度(让我们称之为" 平坦 ").
然后我尝试使用int[] ID数组和double[] 值数组更改关联数组乘法的实现,在两个ID数组上一起移动并在它们相等时相乘(让我们称之为" double ").
然后,我尝试使用F5或Ctrl- 运行所有三个版本的调试或发布F5.结果如下: …
我正在寻找一种为任何对象创建通用包装器的方法.
包装器对象的行为就像它包装的类一样,但是可以有更多的属性,变量,方法等,例如对象计数,缓存等.
假设包装类叫做Wrapper,要包装的类叫做Square,并且有构造函数Square(double edge_len)和属性/方法EdgeLength和Area,我想用它如下:
Wrapper<Square> mySquare = new Wrapper<Square>(2.5); /* or */ new Square(2.5);
Console.Write("Edge {0} -> Area {1}", mySquare.EdgeLength, mySquare.Area);
Run Code Online (Sandbox Code Playgroud)
显然我可以为我想要包装的每个类创建一个这样的包装类,但我正在寻找一个通用的解决方案,即Wrapper<T>可以处理原始类型和复合类型(尽管在我目前的情况下,我会很高兴只包装我自己的类).
建议?
谢谢.
继续从了解VS2010 C#并行性能分析结果的讨论,但更重要的是:
我有许多并行工作的线程(使用Parallel.For/Each),它们为小类使用许多内存分配.
这会在全局内存分配器线程上产生争用.
有没有办法指示.NET为每个线程预分配内存池并从该池中进行所有分配?
目前我的解决方案是我自己的内存池实现(全局分配的类型为T的对象数组,它们在线程中循环使用)这有很大帮助,但效率不高,因为:
谢谢,
哈该