我有一些经过大量优化的数学函数需要1-2 nanoseconds完成.这些功能每秒被称为数亿次,因此尽管性能已经非常出色,但呼叫开销仍是一个问题.
为了保持程序的可维护性,提供这些方法的类继承了一个IMathFunction接口,以便其他对象可以直接存储特定的数学函数并在需要时使用它.
public interface IMathFunction
{
double Calculate(double input);
double Derivate(double input);
}
public SomeObject
{
// Note: There are cases where this is mutable
private readonly IMathFunction mathFunction_;
public double SomeWork(double input, double step)
{
var f = mathFunction_.Calculate(input);
var dv = mathFunction_.Derivate(input);
return f - (dv * step);
}
}
Run Code Online (Sandbox Code Playgroud)
由于消费代码使用它,这种接口与直接呼叫相比造成了巨大的开销.一个直接调用需要1-2ns,而虚拟接口调用需要8-9ns.显然,接口的存在及其随后的虚拟呼叫转换是这种情况的瓶颈.
如果可能的话,我想保留可维护性和性能.有没有办法在实例化对象时将虚函数解析为直接调用,以便所有后续调用都能够避免开销?我认为这将涉及用IL创建委托,但我不知道从哪里开始.
似乎我遇到的每个帖子都达成了相同的共识:仅返回字段的属性由JIT内联,并且具有与字段几乎相同的性能.
但是,我目前的情况似乎并非如此.我的程序进行密集计算,访问许多属性,这些属性只是自动获取器和私有设置器.但是,在这种特殊情况下,我只是复制一个对象.
在启用优化的情况下在发布模式下分析代码会导致get对属性函数的许多调用.Copy()总呼叫总计约5.6ms.
但是,当属性转换为字段时,函数运行速度比使用属性快6倍:
与使用字段相比,比较两个属性的相等性似乎会产生更多的性能损失.这是类IEquatable实现的基准,使用相同的代码,但使用字段交换属性.
如果JIT应该通过内联来优化属性,为什么会出现?我想保留属性,因为它们的访问控制方面非常方便,但如果它们这么慢,我会坚持使用字段.
编辑:似乎受此问题影响的一些(但不是全部)案例正在使用在接口中声明的属性.在这些情况下没有使用其他多态性,但在这些情况下,删除接口会将性能差异带入预期的水平.
编辑2:如前面的编辑所述,似乎问题的一部分是由于接口虚拟调用.经过更多调查后,似乎在CLR中运行基准测试正确地内联属性,但JetBrains dotTrace没有,即使选中"启用内联"也是如此.
我正在使用 dotTrace 分析一个高度并行的项目,并注意到 CLR 花费了近 50% 的时间来等待ntdll.dll. 我很难弄清楚将其归因于什么。
有没有办法可以确定是什么导致 CLR 花费如此多的时间来调用内核?我已经将这个项目开发为尽可能低分配,并且与运行时间相比,垃圾收集的使用可以忽略不计。我能想到的唯一原因是内存延迟或 CPU 缓存未命中,因为一些 CPU 密集型计算利用随机内存访问。
要添加foreach对自定义集合的支持,您需要实现IEnumerable. 阵列,但是,是特殊的,因为它们基本上是编译成一个范围为基础的循环,这是很多比使用一个IEnumerable更快。一个简单的基准测试证实:
number of elements: 20,000,000
byte[]: 6.860ms
byte[] as IEnumerable<byte>: 89.444ms
CustomCollection.IEnumerator<byte>: 89.667ms
Run Code Online (Sandbox Code Playgroud)
基准:
private byte[] byteArray = new byte[20000000];
private CustomCollection<byte> collection = new CustomCollection<T>( 20000000 );
[Benchmark]
public void enumerateByteArray()
{
var counter = 0;
foreach( var item in byteArray )
counter += item;
}
[Benchmark]
public void enumerateByteArrayAsIEnumerable()
{
var counter = 0;
var casted = (IEnumerable<byte>) byteArray;
foreach( var item in casted )
counter += item;
}
[Benchmark]
public …Run Code Online (Sandbox Code Playgroud) 我试图通过利用System.Numerics在数组上执行 SIMD 操作来提高 .NET Core 库的性能float[]。System.Numerics现在有点时髦,我很难看出它有什么好处。我知道,为了看到 SIMD 的性能提升,必须通过大量计算进行摊销,但考虑到它目前的实现方式,我不知道如何实现这一点。
Vector<float>需要 8 个float值 - 不多也不少。如果我想对一组小于 8 的值执行 SIMD 运算,我必须将这些值复制到一个新数组,并用零填充余数。如果该组值大于 8,我需要复制这些值,用零填充以确保其长度与 8 的倍数对齐,然后循环它们。长度要求是有道理的,但适应这一点似乎是抵消任何性能增益的好方法。
我编写了一个测试包装类来处理填充和对齐:
public readonly struct VectorWrapper<T>
where T : unmanaged
{
#region Data Members
public readonly int Length;
private readonly T[] data_;
#endregion
#region Constructor
public VectorWrapper( T[] data )
{
Length = data.Length;
var stepSize = Vector<T>.Count;
var bufferedLength = data.Length - ( data.Length % stepSize ) + stepSize;
data_ = …Run Code Online (Sandbox Code Playgroud) 当鼠标悬停在表格行上时,我在表格行上添加了一个轻微的框阴影,以便它更加明显。它按预期工作,但是当我添加交替行颜色时,它停止正确显示。
<div class="search-table">
<table>
<tbody>
<tr>
<td>A1</td>
<td>A2</td>
</tr>
<tr class="alt">
<td>B1</td>
<td>B2</td>
</tr>
<tr>
<td>C1</td>
<td>C2</td>
</tr>
<tr class="alt">
<td>C1</td>
<td>C2</td>
</tr>
</tbody>
</table>
</div>
<style>
.search-table {
display: block;
background-color: #535353;
font: normal 12px/150% Arial, Helvetica, sans-serif;
overflow: hidden;
border: 1px solid #8C8C8C;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
.search-table a {
color: #424242;
}
.search-table table {
border-collapse: collapse;
text-align: left;
width: 100%;
background-color: #ffffff;
}
.search-table table td, .search-table table th {
padding: …Run Code Online (Sandbox Code Playgroud) 我正在使用 SQL Server 来存储数千万条记录。我需要能够查询其表以查找 Id 列中存在间隙的缺失行,因为应该没有间隙。
我目前正在使用我在 StackOverflow 上找到的解决方案:
CREATE PROCEDURE [dbo].[find_missing_ids]
@Table NVARCHAR(128)
AS
BEGIN
DECLARE @query NVARCHAR(MAX)
SET @query = 'WITH Missing (missnum, maxid) '
+ N'AS '
+ N'('
+ N' SELECT 1 AS missnum, (select max(Id) from ' + @Table + ') '
+ N' UNION ALL '
+ N' SELECT missnum + 1, maxid FROM Missing '
+ N' WHERE missnum < maxid '
+ N') '
+ N'SELECT missnum '
+ N'FROM Missing ' …Run Code Online (Sandbox Code Playgroud) c# ×5
.net ×2
.net-core ×1
box-shadow ×1
css ×1
field ×1
ienumerable ×1
jit ×1
performance ×1
profiling ×1
properties ×1
roslyn ×1
simd ×1
sql-server ×1
t-sql ×1