- 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/
注意:这与 this other question 相似,但不完全相同 我已经实现了一个 IBusinessCollection界面。它来自 ICollection ,以及旧的非通用 ICollect
配置 AutoMapper 以映射的最佳/最简单方法是什么 ICollection至 ICollection至 ICollection ? 我有一个如下所示的 DomainModel: public
只想对syntactic sygar做简单的扩展: public static bool IsNotEmpty(this ICollection obj) { return ((obj !=
这个问题在这里已经有了答案: Why does IEnumerable inherit from IEnumerable? (4 个回答) 8年前关闭。 IEnumerable实现 IEnumerab
我正在尝试编写一个查询,从我的连接数据中获取国家列表。 Places是List . var zonedCountries = (from dz in db.DeliveryZones.
我有一组消息,每个消息定义为: namespace DatabaseDesign.Models { public class PrivateMessageDetail {
C# 中的 ICollection 中是否有一些方法可以添加另一个集合的所有元素?现在我必须始终为此编写 foreach 循环: ICollection allLetters = ... //some
转换 ICollection 的推荐方式是什么?至 ICollection其中 Bar工具 IBar ? 是不是就这么简单 collection = new List(); ICollection =
我用网格创建了表单来可视化任何集合( ICollection , ICollection )对象。 之后我创建了调试器可视化类(从 Microsoft.VisualStudio.DebuggerVis
我正在尝试基于 Stack 创建自定义集合.当我看 Stack [来自元数据] 在 Visual Studio 中,它显示 Stack实现 ICollection ,这将要求它实现 ICollecti
例如: public interface IFoo { //... ICollection Children { get; } //... } public class Foo
这个问题在这里已经有了答案: Why is it considered bad to expose List? [duplicate] (6 个答案) 关闭 9 年前。 我正在使用 FxCop 工具
这个问题在这里已经有了答案: Why does List implement IList, ICollection and IEnumerable? (4 个答案) 关闭 7 年前。 为什么ILis
我正在使用用 C# 创建的库。我一直致力于将一些代码移植到 F#,但必须使用 C# 库中的相当多的基础类型。 一段代码需要计算一个值列表并将其分配给类中的公共(public)字段/属性。该字段是一个包
此代码不起作用,但是: public virtual ICollection items { get { return (ICollection)items.Where(e => e.isVisibl
这个问题在这里已经有了答案: C# - sorting by a property (3 个答案) how to sort a collection by datetime in c# (4 个答案
这很奇怪,我试图在我的构造函数中使用 List 初始化我的 ICollection 并且发生了这种情况: Schedules = new List(); //OK CateringItems = ne
我想遍历设备上安装的所有语音。 在 TextSoSpeech 元数据中,我看到有 namespace Android.Speech.Tts { public class TextToSpeec
我有以下代码。为什么它总是采用“take(ICollection a)”方法?我认为它自己的对象应该是 LinkedList 或 HashSet,所以它应该调用另外两个 take 方法。 class
我的应用程序客户端/服务器有问题。我使用 MVVM 模式。在我看来,我有一个 DataGrid,它在我的 ViewModel 中与一个 ICollection 绑定(bind),代码行如下: publ
我是一名优秀的程序员,十分优秀!