- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
分析我的 C# 应用程序表明在 List<T>.AddRange
上花费了大量时间.用Reflector看这个方法中的代码表明它调用了List<T>.InsertRange
这是这样实现的:
public void InsertRange(int index, IEnumerable<T> collection)
{
if (collection == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
}
if (index > this._size)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
}
ICollection<T> is2 = collection as ICollection<T>;
if (is2 != null)
{
int count = is2.Count;
if (count > 0)
{
this.EnsureCapacity(this._size + count);
if (index < this._size)
{
Array.Copy(this._items, index, this._items, index + count, this._size - index);
}
if (this == is2)
{
Array.Copy(this._items, 0, this._items, index, index);
Array.Copy(this._items, (int) (index + count), this._items, (int) (index * 2), (int) (this._size - index));
}
else
{
T[] array = new T[count]; // (*)
is2.CopyTo(array, 0); // (*)
array.CopyTo(this._items, index); // (*)
}
this._size += count;
}
}
else
{
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
while (enumerator.MoveNext())
{
this.Insert(index++, enumerator.Current);
}
}
}
this._version++;
}
private T[] _items;
有人会争辩说接口(interface)的简单性(只有一个 InsertRange 重载)证明了运行时类型检查和转换的性能开销是合理的。但是我用 (*)
表示的 3 行背后的原因可能是什么? ?我认为它可以重写为更快的替代方案:
is2.CopyTo(this._items, index);
您认为有什么理由不使用这种更简单且显然更快的替代方案吗?
编辑:
感谢您的回答。因此,一致认为这是一种保护措施,可防止以有缺陷/恶意的方式实现 CopyTo 的输入集合。对我来说,不断付出以下代价似乎有点矫枉过正:1) 运行时类型检查 2) 临时数组的动态分配 3) 复制操作加倍,而所有这些都可以通过定义 2 个或更多 InsertRange 重载来保存, 一得到 IEnumerable
和现在一样,第二个获得 List<T>
, 第三次得到T[]
.后两者的实现速度可能是当前情况的两倍。
编辑 2:
我确实实现了一个 FastList 类,与 List 相同,除了它还提供了一个带有 T[] 参数的 AddRange 重载。此重载不需要动态类型验证和元素的双重复制。我确实通过将 4 字节数组添加到最初为空的列表 1000 次来针对 List.AddRange 分析此 FastList.AddRange。我的实现以 9 倍(九!)击败了标准 List.AddRange 的速度。 List.AddRange 在我们应用程序的一个重要使用场景中占用大约 5% 的运行时间,用提供更快 AddRange 的类替换 List 可以将应用程序运行时间提高 4%。
最佳答案
他们正在阻止 ICollection<T>
的实现从访问插入范围之外的目标列表的索引。上面的实现导致 IndexOutOfBoundsException
如果 CopyTo
的错误(或“操纵”)实现被称为。
请记住 T[].CopyTo
实际上在内部实现为 memcpy
,因此添加该行的性能开销很小。当您以如此低的成本为大量调用增加安全性时,您不妨这样做。
编辑: 我觉得奇怪的部分是对 ICollection<T>.CopyTo
的调用(复制到临时数组)不会在调用 EnsureCapacity
后立即发生.如果它被移动到那个位置,那么跟随任何 synchronous exception该 list 将保持不变。按原样,该条件仅在插入发生在列表末尾时成立。这里的推理是:
Array.Copy
不能失败因为
ICollection.CopyTo
的外部调用以及调整列表大小和分配临时数组所需的分配。如果所有这三个都发生在为插入而移动元素之前,则更改列表的事务不能抛出同步异常。编辑 2(对 OP 编辑的回应):您对此进行了分析吗?您大胆地声称 Microsoft 应该选择更复杂的 API,因此您应该确保当前方法速度慢的断言是正确的。我从来没有遇到过 InsertRange
的性能问题,而且我很确定,与重新实现动态列表相比,重新设计算法可以更好地解决某人确实面临的任何性能问题。为了不让您认为我在消极方面很苛刻,请记住以下几点:
关于c# - List<T>.AddRange 实现次优,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2123161/
我在家里的电脑上玩 Entity Framework 6,决定尝试插入相当多的行,大约 430k。 我的第一次尝试是这样的,是的,我知道它可以做得更好,但无论如何都是为了研究: var watch =
这个问题在这里已经有了答案: Nested object initializer syntax (1 个回答) 关闭 5 年前。 有一个 C# 功能,我不知道它的术语,因此无法找到关于它的文档。 允
我有一些遗留的 C# 代码,其中包含以下部分: private List mList = new List(); public List getList() { List list = new
通用列表中是否有内置函数可以从特定索引中的另一个列表中添加范围,还是我必须自己编写? 例如: List list1 = new List(); List list2 = new List(); lis
在下面的代码中: var cats = new List() {"cat1", "cat2"}; var dogs = new List() {"dog1", "dog2"}; var animals
具有讽刺意味的是,在将一堆旧 Arraylist 转换为使用通用 List(Of foo) 集合时,为了提高类型安全性,我在 List.AddRange() 中遇到了意外行为方法。 鉴于以下代码,我预
项目:我有一个包含 ComboBox 和 FlowLayoutPanel 的父面板。 FlowLayoutPanel 包含数量可变的子面板(继承自 UserControl 的自定义控件)。每个子面板包
我正在为 ObservableCollection 编写一个扩展方法,并且已了解到 .Add 函数每次调用都会引发 3 个属性更改事件, 所以这样的事情是一个坏主意: public static vo
这个问题在这里已经有了答案: Selection.addRange() is deprecated and will be removed from Chrome (1 个回答) 关闭 5 年前。
基本上我正在寻找这样的东西...... cbo_Genre.Items.AddRange({"Horror", "Comedy"}); 最佳答案 看看这个。 ComboBox1.Items.AddRa
如果我有这两个类: class A {} class B : A {} 我制作了一个 List 但我想通过调用 List.AddRange(List) 添加一个 List 但编译器拒绝: Argume
比如说,我有 3 个列表 List l1 List l1,l2,l3 所有 3 个列表都有很多项目我想将它们全部添加到一个列表中 List finalList finalList.AddRange(l
我坚信 ToolStripItemCollection.AddRange 的实现是一个错误: 我制作了带有两个菜单的 Windows 窗体应用程序,每个菜单包含 2 个项目。 first menu s
此问题中的代码生成以下 JSON。 代码应该根据 .Where(a => a.Values != null) 行排除空的“子”键,但它不起作用。 我可以在哪里放置 where 子句,以便 JSON 不
在HttpWebRequest 的AddRange 方法中,我们可以指定要下载的字节范围。我想知道的是如何指定从某个偏移量到文件末尾的范围。 比如如果我们不知道文件的长度,我们可以在Request H
我已经安装了 Connector/NET 6.5.4。在 VisualStutio 中,IntelliSense 建议使用一种名为 MySqlParameterCollection.AddRange
这似乎是一个简单的问题,但对我来说不是,而且搜索也没有结果。到目前为止,我唯一完成的 .net 编程是使用 Delphi Prism。使用 Prism,我可以执行以下操作: var l := new
“源数组不够长。检查 srcIndex 和长度,以及数组的下限。” 我在创建目标列表(在我添加对象的地方)和源列表(从我在目标列表中添加对象的地方)时没有提到任何大小 这是我正在做的类似代码。 Lis
namespace SubscriptionWebsite.PlaceHolders { public class TreeData { public int ID {
我想做的是 FreezableCollection.AddRange(collectionToAdd) 每次我添加到 FreezableCollection 时都会引发一个事件并发生一些事情。现在我有
我是一名优秀的程序员,十分优秀!