Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么要列出此列表<>;。代码索引比列表[i]和手动比较快得多?_C#_Performance_Indexof - Fatal编程技术网

C# 为什么要列出此列表<>;。代码索引比列表[i]和手动比较快得多?

C# 为什么要列出此列表<>;。代码索引比列表[i]和手动比较快得多?,c#,performance,indexof,C#,Performance,Indexof,我在这段代码上运行AQTime,我发现。IndexOf需要16%的时间,而另一段则需要接近80%的时间。。。他们似乎使用相同的等质量和其他例程。调用116000次,插入30000项。列表对象中没有一个包含超过200个元素。(我可能没有正确使用AQTime,我正在调查此事) class PointD:IEquatable { 公共双X,Y,Z; 布尔等式等于(点D其他) { 返回((X==other.X)&&(Y==other.Y)&&&(Z==other.Z)); } } 类性能测试 { 只读列

我在这段代码上运行AQTime,我发现。IndexOf需要16%的时间,而另一段则需要接近80%的时间。。。他们似乎使用相同的等质量和其他例程。调用116000次,插入30000项。列表对象中没有一个包含超过200个元素。(我可能没有正确使用AQTime,我正在调查此事)

class PointD:IEquatable
{
公共双X,Y,Z;
布尔等式等于(点D其他)
{
返回((X==other.X)&&(Y==other.Y)&&&(Z==other.Z));
}
}
类性能测试
{
只读列表_pCoord3Points=新列表();
公共点;
公共积分;
公共性能测试()
{
NewPoints=0;
总分=0;
}
公共int检查点indexof(PointD pt)
{
int retIndex=_pCoord3Points.IndexOf(pt);
如果(视网膜指数<0)
{
_PCoord3点。添加(pt);
NewPoints++;
}
TotalPoints++;
返回retIndex;
}
公共int检查点FORBREAK(点式pt)
{
int-retIndex=-1;
对于(int i=0;i<_pCoord3Points.Count;i++)
{
PointD otherPt=_pcoord3点[i];
如果((pt.X==otherPt.X)&&
(第Y部分==其他第Y部分)&&
(第Z部分=其他第Z部分))
{
retIndex=i;
打破
}
}
如果(retIndex==-1)
{
NewPoints++;
_PCoord3点。添加(pt);
}
TotalPoints++;
返回retIndex;
}
静态void Main()
{
常数int xmax=300;
常数int ymax=10;
常数int zmax=10;
常数int imax=4;
var test=新的PerfTest();
//test.Init();
秒表sw=Stopwatch.StartNew();
对于(int i=0;i
什么类型的
\u pCoord3Points
?如果元素类型是仅覆盖
Equals(object)
的值类型,则
IndexOf
可能会重复装箱值以检查是否相等。这也许可以解释。这真的只是猜测在这一点上虽然。。。如果您可以提供一个简短但完整的程序来演示问题,这将使您更容易获得帮助。

通常,在您访问数组元素之前,它会检查以确保索引>=0且 不用说,如果循环中的代码很少,那么这会影响性能。为了减少这个问题,JIT编译器为(i=0;i优化形式为
的循环——也就是说,任何访问数组从0到长度-1的所有索引的循环。它省略了这种情况下的边界检查。(如果您访问数组[i+1]之类的东西,优化就会失败,因为您可能会越界。)

不幸的是,这只适用于数组,而不适用于列表。因此,后面的代码将不会得到优化

但是,由于列表内部包含一个数组,并且List.IndexOf()使用循环直接访问数组中的每个值,因此可以对其进行优化

顺便说一句,说(inti=0;i
比说
intlength=array.Length;对于(int i=0;i
——因为它不能确定
length
是否真的是数组的长度

编辑:使用Reflector查看IndexOf代码,循环确实会优化,但正如其他人所提到的,它调用Equals()——这需要一个和各种健全性检查。因此,在本例中,当您不使用探查器运行IndexOf时,它实际上可能会慢一些

反汇编代码:

internal virtual int IndexOf(T[] array, T value, int startIndex, int count)
{
    int num = startIndex + count;
    for (int i = startIndex; i < num; i++)
    {
        if (this.Equals(array[i], value))
        {
            return i;
        }
    }
    return -1;
}
内部虚int IndexOf(T[]数组,T值,int startIndex,int计数)
{
int num=开始索引+计数;
对于(int i=startIndex;i
我做了以下假设:

  • PointD
    是一个结构
  • IndexOf
    确实比手动迭代列表要慢
通过实现
IEquatable
接口,您可以加速
IndexOf

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);
    }
}
在Windows 7、x64、.NET 4.0 x64 build上,我得到以下计时(大约):

使用
struct PointD
实现
IEquatable时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);
    }
}
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);
    }
}
IndexOf: 00:00:04.8096623 For Loop: 00:00:00.0014203 IndexOf: 00:00:01.0703627 For Loop: 00:00:00.0014190 IndexOf: 00:00:00.3904615 For Loop: 00:00:00.0015218