之前我问了一个问题,为什么我看到这么多的例子都使用了这个var关键字并得到了答案,虽然它只是匿名类型所必需的,但它仍然被用来使编写代码"更快"/更容易和"只是因为".
在这个链接("C#3.0 - Var不是Objec")之后,我看到它var被编译成IL中的正确类型(你会在中间的文章中看到它).
我的问题是IL代码使用var关键字take 会有多少(如果有的话),如果在任何地方使用它,它是否会接近于对代码性能有可衡量的水平?
在这种情况下,使用泛型与接口有什么实际优势:
void MyMethod(IFoo f)
{
}
void MyMethod<T>(T f) : where T : IFoo
{
}
Run Code Online (Sandbox Code Playgroud)
即你能做什么MyMethod<T>,你不能在非通用版本?我正在寻找一个实际的例子,我知道理论上的差异是什么.
我知道,在MyMethod<T>T 中,T将是具体的类型,但是我只能在方法体内将它用作IFoo.那么什么才是真正的优势呢?
我很好奇Expression.Compile与代码中的lambda表达式和直接方法使用的性能如何,以及直接方法调用与虚方法调用(伪代码):
var foo = new Foo();
var iFoo = (IFoo)foo;
foo.Bar();
iFoo.Bar();
(() => foo.Bar())();
(() => iFoo.Bar())();
Expression.Compile(foo, Foo.Bar)();
Expression.Compile(iFoo, IFoo.Bar)();
Expression.CompileToMethod(foo, Foo.Bar);
Expression.CompileToMethod(iFoo, IFoo.Bar);
MethodInfo.Invoke(foo, Foo.Bar);
MethodInfo.Invoke(iFoo, IFoo.Bar);
Run Code Online (Sandbox Code Playgroud) 我遇到了一些规则(建议)使用混凝土List和Dictionary,而不是IList和IDictionary给予,显示通过该接口访问样本测试是相当慢一点.例如,将10000个值添加到列表然后Count在列表上执行10亿次表示通过接口执行此操作比通过具体类执行它慢28倍.即,通过具体类需要80ms,通过界面需要2800ms,这表明它通过界面的速度非常慢.鉴于此,使用具体类是合理的.有没有理由说接口这么慢?(可能更多的是针对那些了解更多关于.net内部的人).
似乎我遇到的每个帖子都达成了相同的共识:仅返回字段的属性由JIT内联,并且具有与字段几乎相同的性能.
但是,我目前的情况似乎并非如此.我的程序进行密集计算,访问许多属性,这些属性只是自动获取器和私有设置器.但是,在这种特殊情况下,我只是复制一个对象.
在启用优化的情况下在发布模式下分析代码会导致get对属性函数的许多调用.Copy()总呼叫总计约5.6ms.
但是,当属性转换为字段时,函数运行速度比使用属性快6倍:
与使用字段相比,比较两个属性的相等性似乎会产生更多的性能损失.这是类IEquatable实现的基准,使用相同的代码,但使用字段交换属性.
如果JIT应该通过内联来优化属性,为什么会出现?我想保留属性,因为它们的访问控制方面非常方便,但如果它们这么慢,我会坚持使用字段.
编辑:似乎受此问题影响的一些(但不是全部)案例正在使用在接口中声明的属性.在这些情况下没有使用其他多态性,但在这些情况下,删除接口会将性能差异带入预期的水平.
编辑2:如前面的编辑所述,似乎问题的一部分是由于接口虚拟调用.经过更多调查后,似乎在CLR中运行基准测试正确地内联属性,但JetBrains dotTrace没有,即使选中"启用内联"也是如此.
所以, first(FirstOrDefault(predicate)) 一个在性能方面更好1
我明白了,我也认为再调用一个方法应该稍微慢一点,这只是我的直觉。尽管如此,我还是决定运行一些基准测试来证明我的权利,而我却知之甚少。
这是我运行基准测试的结果:
BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363
Intel Core i7-3630QM CPU 2.40GHz (Ivy Bridge), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.101
[Host] : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
Job-XMZTSC : .NET Framework 4.8 (4.8.4121.0), X64 RyuJIT
Runtime=.NET 4.7.2
Method N Mean Error StdDev Ratio RatioSD
WherePlusFirstOrDefaultArray 10000 31.44 us 0.288 us 0.270 us 0.40 0.00
FirstOrDefaultArray 10000 78.47 us 0.679 us 0.635 us 1.00 …Run Code Online (Sandbox Code Playgroud) 现在,我使用以下代码创建一个Shuffle扩展:
public static class SiteItemExtensions
{
public static void Shuffle<T>(this IList<T> list)
{
var rng = new Random();
int n = list.Count;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我正在寻找一种更快,更有效的方法来做到这一点.现在,使用秒表类,大约需要20秒来洗牌100,000,000件物品.有没有人有任何想法让这更快?
我真的不明白两者之间有什么区别:
private void Send<T>(T packet) where T : IPacket
Run Code Online (Sandbox Code Playgroud)
和
private void Send(IPacket packet)
Run Code Online (Sandbox Code Playgroud)
既然通用有限制,那不是一模一样吗?如果不是,那么这里的区别是什么?使用带有约束的通用方法相对于简单方法有什么优点?
谢谢!
我有一个接口I,一个抽象类A,这两者的具体类,以及一个C用作基线的具体类.
interface I
{
void Do();
}
abstract class A
{
public abstract void Do();
}
class C
{
public void Do() {}
}
class IImpl : I
{
public void Do() {}
}
class AImpl : A
{
public override void Do() {}
}
Run Code Online (Sandbox Code Playgroud)
我对基准通话C.Do(),I.Do()并A.Do()使用BenchmarkDotNet.
public class Bench
{
private C _c;
private I _i;
private A _a;
[Setup]
public void Setup()
{
_c = …Run Code Online (Sandbox Code Playgroud) 假设我有一个包含 3 个方法的接口,即 m1()、m2()、m3(),并且我有一个抽象类仅包含抽象方法,即 m1()、m2()、m3()。假设这个抽象类或接口将来不会改变。在这种情况下我应该选择什么以及为什么?他们中的任何一个会有更好的表现吗?
c# ×10
performance ×5
.net ×3
benchmarking ×2
generics ×2
abstract ×1
clr ×1
expression ×1
field ×1
interface ×1
jit ×1
lambda ×1
linq ×1
oop ×1
parameters ×1
polymorphism ×1
properties ×1
var ×1
variables ×1