- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
最近我一直在研究编写返回集合的函数的一些约定。我想知道实际使用 List<int>
的函数是否应该返回 List<int>
或者更确切地说 IList<int>
, ICollection<int>
或 IEnumerable<int>
.我创建了一些性能测试,我对结果感到非常惊讶。
static List<int> list = MakeList();
static IList<int> iList = MakeList();
static ICollection<int> iCollection = MakeList();
static IEnumerable<int> iEnumerable = MakeList();
public static TimeSpan Measure(Action f)
{
var stopWatch = new Stopwatch();
stopWatch.Start();
f();
stopWatch.Stop();
return stopWatch.Elapsed;
}
public static List<int> MakeList()
{
var list = new List<int>();
for (int i = 0; i < 100; ++i)
{
list.Add(i);
}
return list;
}
public static void Main()
{
var time1 = Measure(() => { // Measure time of enumerating List<int>
for (int i = 1000000; i > 0; i-- ) {
foreach (var item in list)
{
var x = item;
}
}
});
Console.WriteLine($"List<int> time: {time1}");
var time2 = Measure(() => { // IList<int>
for (int i = 1000000; i > 0; i-- ) {
foreach (var item in iList)
{
var x = item;
}
}
});
Console.WriteLine($"IList<int> time: {time2}");
var time3 = Measure(() => { // ICollection<int>
for (int i = 1000000; i > 0; i-- ) {
foreach (var item in iCollection)
{
var x = item;
}
}
});
Console.WriteLine($"ICollection<int> time: {time3}");
var time4 = Measure(() => { // IEnumerable<int>
for (int i = 1000000; i > 0; i-- ) {
foreach (var item in iEnumerable)
{
var x = item;
}
}
});
Console.WriteLine($"IEnumerable<int> time: {time4}");
}
输出:
List<int> time: 00:00:00.7976577
IList<int> time: 00:00:01.5599382
ICollection<int> time: 00:00:01.7323919
IEnumerable<int> time: 00:00:01.6075277
我尝试了不同的措施顺序或制作 MakeList()
返回上述接口(interface)之一,但所有接口(interface)仅确认返回 List<int>
并将其处理为 List<int>
速度大约是接口(interface)的两倍。
但是各种来源,包括this answer声称你永远不应该返回List<>
并始终使用界面。
所以我的问题是:
List<int>
大约是接口(interface)速度的两倍?最佳答案
Why is processing a
List<int>
about twice as fast as the interfaces?
好问题。当试图 foreach
某些东西,C# 首先 检查集合的类型是否已经有一个名为 GetEnumerator
的方法返回具有 MoveNext
的类型和 Current
.如果是,它会直接调用它们。如果不是,则返回使用 IEnumerable<T>
或 IEnumerable
和 IEnumerator<T>
或 IEnumerator
获取枚举器,以便它可以调用 MoveNext
和 Current
.
做出这种设计选择有两个原因。首先,在泛型之前的 C# 1.0 世界中,这意味着您可以调用 Current
返回 int
; IEnumerator.Current
当然是object
所以会装箱 int
,这既是速度又是内存损失。其次,这意味着集合的作者可以做实验来找出 MoveNext
的哪个实现。和 Current
表现最好。
List<T>
的实现者正是这样做的;如果你检查 GetEnumerator
在 List<T>
你会发现一些有趣的事情:它返回一个可变值类型。是的,可变值类型被认为是一种容易被滥用的不良做法。但是因为 GetEnumerator
的这个重载使用了 99.999% foreach
代表您调用,绝大多数时候您甚至都不会注意到有一个可变值供您滥用,因此不要滥用它。
(注意:前一段的要点不应该是“使用可变值类型,因为它们很快”。要点应该是了解用户的使用模式,然后设计一个安全、高效的工具来满足他们的需求。通常可变值类型不是正确的工具。)
总之,长话短说,我们通过在迭代编译时已知为 List<T>
的对象时直接绑定(bind)到可变值类型的方法来避免各种虚拟调用、接口(interface)类型检查等。 .
What should we return from a function and how to manage the code if we care about performance?
如果您关心速度性能,那么您应该关注程序中最慢的部分。程序中最慢的是调用 MoveNext
在一个集合?如果是这样,恭喜你,你有一个非常快的程序; MoveNext
是接下来要优化的事情。但在这种情况下,你真的应该问“我如何完全避免或延迟这个循环?”如果你在那条船上。
如果MoveNext
不是程序中最慢的东西那么谁在乎它在特定实现中是否慢了几纳秒? 返回逻辑上最接近调用者想要和需要的类型,不用担心微小的损失。
关于c# - 枚举列表比 IList、ICollection 和 IEnumerable 更快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58410905/
我正在尝试转换 IList>至 IList ,我的意思是有一个唯一的列表,其中包含第一个的所有元素(对象)。 public IList> PMTs { get
在 C# 中,如果我有一个 IList,但我不知道 IList 中对象的类型,我该如何创建一个 的副本>IList? 情况是这样的: 我有一个 CollectionEditor,它可以修改 IList
IList不继承 IList其中 IEnumerable继承IEnumerable . 如果out修饰符是大多数执行 IList 的唯一原因(例如 Collection , List )实现 ILis
尝试过: IList> matrix = new List()>(); 可是我做不到。我该怎么做?我需要一个字符串矩阵... 最佳答案 你需要: IList> matrix = new List>()
我有一个构建列表列表的方法。我想让返回类型使用通用 IList<> 接口(interface)来减少与下游具体 List<> 类型的耦合。但是,编译器在类型转换方面遇到了困难。 public ILis
我有一个 IList我想将此集合复制到 IList收藏 我试过这个: IList listAdminVAT = new AdministrationService(session).ListDecim
我有一个实现了 IList 的对象接口(interface),我想把它转换成IList或者 List ,我试过了 IList a=(IList)b; List a=(IList)b; IList a=
我似乎无法弄清楚为什么以下内容不起作用。 通过阅读,它似乎一定与 this 之类的东西有某种关联。 . public class Test { public void SomeFunction
我有几个类: class Vehicle { } class Car : Vehicle { } 我有一个派生类的列表: IList cars; 我想将列表转换为其基类,并尝试过: IList bas
List的定义在 .net 中显示它实现了各种接口(interface)。 public class List : IList, ICollection, IEnumerable, IList, IC
我想创建一个 ListCollectionView使用通用 IList但是构造函数得到一个非泛型 IList .如何将我的列表从 IList 转换为至 IList ? 如果有另一种方法可以创建 Lis
这个问题在这里已经有了答案: Remove items from one list in another (10 个答案) 关闭 8 年前。 很抱歉提出这样的基本问题,我是 LINQ 的新手,我正试
我正在实现 IListSource这需要一个方法 GetList()具有以下签名: IList GetList() 我正在使用 .NET Framework 2,我想返回一个实现 IList 的对象,
我有一个类(class)想要 IList , 但我有一个 Systems.Collection.IList , 来自 NHibernate 问题。 我想创建一个将其转换为 IList 的方法.我该怎么
我似乎找不到为我的 MVVM Xamarin 表单应用程序构建和使用数据的最佳实践或最佳机制。这可能是对如何解决问题的简单误解,但我不确定。 我曾尝试使用 IEnumerable、IList 和一个简
多年来,我们大部分时间都在使用泛型集合。有时我们确实需要任何东西的集合(好吧,通常只有一些不同的东西但没有公共(public)基类)。对于这种情况,我们可以使用 IList或通用 IList作为方法参
我有一个 IList目的。 Person 类有字段,FirstName , LastName等 我有一个函数需要 IList我想以与 IList 相同的顺序传入 FirstNames 列表目的。有没有
尝试这样转换 Products1 = (IList)basicProfile.Products2.Select(ToProductInfo) Products1 是一个 public IList Pr
我正在尝试创建一个列表列表,但在实例化列表时遇到了问题。 IList> allLists = List>(); 我遇到了这一行的编译错误。 最佳答案 你必须实例化一个 List的 IList , 不是
我有一个集合,它实现了一个扩展 IList 和 List 的接口(interface)。 public Interface IMySpecialCollection : IList, IList {
我是一名优秀的程序员,十分优秀!