gpt4 book ai didi

c# - 为什么这个 List<>.IndexOf 代码比 List[i] 和手动比较快得多?

转载 作者:太空狗 更新时间:2023-10-29 17:43:57 27 4
gpt4 key购买 nike

我在这段代码上运行 AQTime,我发现 .IndexOf 占用了 16% 的时间,而另一段代码占用了接近 80% 的时间……它们似乎使用了相同的 IsEqual 和其他例程。调用 116,000 次插入 30,000 个项目。没有一个 List<> 对象获得超过 200 个元素。 (我可能错误地使用了 AQTime,我正在调查这个)

class PointD : IEquatable<PointD>
{
public double X, Y, Z;

bool IEquatable<PointD>.Equals(PointD other)
{
return ((X == other.X) && (Y == other.Y) && (Z == other.Z));
}
}

class PerfTest
{
readonly List<PointD> _pCoord3Points = new List<PointD>();
public int NewPoints;
public int TotalPoints;

public PerfTest()
{
NewPoints = 0;
TotalPoints = 0;
}
public int CheckPointIndexOf(PointD pt)
{
int retIndex = _pCoord3Points.IndexOf(pt);
if (retIndex < 0)
{
_pCoord3Points.Add(pt);
NewPoints++;
}
TotalPoints++;
return retIndex;
}

public int CheckPointForBreak(PointD pt)
{
int retIndex = -1;
for (int i = 0; i < _pCoord3Points.Count; i++)
{
PointD otherPt = _pCoord3Points[i];
if ((pt.X == otherPt.X) &&
(pt.Y == otherPt.Y) &&
(pt.Z == otherPt.Z))
{
retIndex = i;
break;
}
}
if (retIndex == -1)
{
NewPoints++;
_pCoord3Points.Add(pt);
}
TotalPoints++;
return retIndex;
}

static void Main()
{
const int xmax = 300;
const int ymax = 10;
const int zmax = 10;
const int imax = 4;

var test = new PerfTest();
//test.Init();
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < imax; i++)
{
for (int x = 0; x < xmax; x++)
{
for (int y = 0; y < ymax; y++)
{
for (int z = 0; z < zmax; z++)
{
var pt = new PointD { X = x, Y = y, Z = z };
test.CheckPointIndexOf(pt);
}
}
}

}
sw.Stop();
string output = string.Format("Total: {0:0} New: {1:0} IndexOf: ", test.TotalPoints, test.NewPoints);
Console.Write(output);
Console.WriteLine(sw.Elapsed);

test = new PerfTest();
sw = Stopwatch.StartNew();
for (int i = 0; i < imax; i++)
{
for (int x = 0; x < xmax; x++)
{
for (int y = 0; y < ymax; y++)
{
for (int z = 0; z < zmax; z++)
{
var pt = new PointD { X = x, Y = y, Z = z };
test.CheckPointForBreak(pt);
}
}
}

}
sw.Stop();
output = string.Format("Total: {0:0} New: {1:0} PointD[] ", test.TotalPoints, test.NewPoints);
Console.Write(output);
Console.WriteLine(sw.Elapsed);
Console.ReadLine();
}
}

最佳答案

我做了以下假设:

  • PointD是一个结构
  • IndexOf确实比手动迭代列表慢

可以加快IndexOf通过实现 IEquatable<T>接口(interface):

struct PointD : IEquatable<PointD>
{
public int X;
public int Y;
public int Z;

public bool Equals(PointD other)
{
return (this.X == other.X) &&
(this.Y == other.Y) &&
(this.Z == other.Z);
}
}

没有实现IEquatable<T>界面,IndexOf将比较两者PointD元素使用 ValueType.Equals(object other)这涉及昂贵的装箱操作。

IEquatable<T> 的文档接口(interface)状态:

The IEquatable<T> interface is used by generic collection objects such as Dictionary<TKey, TValue>, List<T>, and LinkedList<T> when testing for equality in such methods as Contains, IndexOf, LastIndexOf, and Remove. It should be implemented for any object that might be stored in a generic collection.

这是我的完整基准代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;

struct PointD
{
public int X;
public int Y;
public int Z;
}

class PerfTest
{
List<PointD> _pCoord3Points = new List<PointD>();

int checkPointIndexOf(PointD pt)
{
return _pCoord3Points.IndexOf(pt);
}

int checkPointForBreak(PointD pt)
{
int retIndex = -1;
for (int i = 0; i < _pCoord3Points.Count; i++)
{
PointD otherPt = _pCoord3Points[i];
if ((pt.X == otherPt.X) &&
(pt.Y == otherPt.Y) &&
(pt.Z == otherPt.Z))
retIndex = i;
break;
}
return retIndex;
}

void init()
{
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 10; y++)
{
for (int z = 0; z < 10; z++)
{
PointD pt = new PointD() { X = x, Y = y, Z = z };
_pCoord3Points.Add(pt);
}
}
}
}

static void Main(string[] args)
{
PerfTest test = new PerfTest();
test.init();
Stopwatch sw = Stopwatch.StartNew();
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 10; y++)
{
for (int z = 0; z < 10; z++)
{
PointD pt = new PointD() { X = x, Y = y, Z = z };
test.checkPointIndexOf(pt);
}
}
}
sw.Stop();
Console.WriteLine(sw.Elapsed);
sw = Stopwatch.StartNew();
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 10; y++)
{
for (int z = 0; z < 10; z++)
{
PointD pt = new PointD() { X = x, Y = y, Z = z };
test.checkPointForBreak(pt);
}
}
}
sw.Stop();
Console.WriteLine(sw.Elapsed);
}
}

在 Windows 7、x64、.NET 4.0 x64 构建上,我得到以下计时(大约):

IndexOf:  00:00:04.8096623For Loop: 00:00:00.0014203

转弯时PointD进入 class时间更改为

IndexOf:  00:00:01.0703627For Loop: 00:00:00.0014190

使用 struct PointD 时实现 IEquatable<PointD>我得到了更多“相似”的结果,但是 IndexOf仍然较慢(现在使用 class 时没有显着差异):

IndexOf:  00:00:00.3904615For Loop: 00:00:00.0015218

关于c# - 为什么这个 List<>.IndexOf 代码比 List[i] 和手动比较快得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3663014/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com