什么时候分配和租用阵列更合适?
When Is it Preferred to Allocate vs Rent an Array?
我目前正在设计一个解决方案,并且发现自己处于一个有趣的性能场景中。我已经放置了一个非常简单的解决方案来演示可以在此处找到的这种情况:
https://github.com/Mike-EEE/Stash/tree/master/AllocationVsRent
这个问题的核心是阵列的分配与租赁。此解决方案中的一种方法执行租赁,如下所示:
[Benchmark]
public int Rented()
{
var array = _pool.Rent(2);
array[0] = 1;
array[1] = 2;
var result = array[0] + array[1];
_pool.Return(array);
return result;
}
另一个执行分配,如下所示:
[Benchmark(Baseline = true)]
public int Allocated()
{
var array = new int[2];
array[0] = 1;
array[1] = 2;
var result = array[0] + array[1];
return result;
}
当运行这两个基准时,我得到以下结果:
BenchmarkDotNet=v0.11.5, OS=Windows 10.0.17763.475 (1809/October2018Update/Redstone5)
AMD Ryzen 7 2700X, 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.0.100-preview5-011568
[Host] : .NET Core 3.0.0-preview5-27626-15 (CoreCLR 4.6.27622.75, CoreFX 4.700.19.22408), 64bit RyuJIT
DefaultJob : .NET Core 3.0.0-preview5-27626-15 (CoreCLR 4.6.27622.75, CoreFX 4.700.19.22408), 64bit RyuJIT
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------- |----------:|----------:|----------:|------:|--------:|-------:|------:|------:|----------:|
| Rented | 29.563 ns | 0.1736 ns | 0.1450 ns | 5.01 | 0.27 | - | - | - | - |
| Allocated | 5.825 ns | 0.1440 ns | 0.2522 ns | 1.00 | 0.00 | 0.0077 | - | - | 32 B |
虽然 Allocated
基准测试速度更快,但它确实调用了垃圾收集。而对于 Rented
基准测试,速度较慢但没有垃圾收集惩罚。
所以我的基本问题是:首选哪一个?即使它确实产生垃圾,也可以进行分配吗?虽然它更快,但我还是觉得它的使用很脏,请原谅双关语。
请注意:我不能使用stackalloc
,因为我的实践场景涉及两种方法之间的调用,据我所知,这排除了使用它的可能性。我当然愿意接受我忽略的任何建议,以便在这里获得两全其美。
提前感谢您的帮助。
由于我的场景涉及太多内容无法进一步解释(这里尽量保持简单),我通过允许最终开发人员决定他们是想要速度还是垃圾来解决这个问题。
关于更多上下文,我正在开发的 API 是 zero-allocation 首要的,速度是一个重要但次要的重点。
在所有其他调用中,API 是 zero-allocation 并且比我正在测试的现有 API 更快,但此调用除外。所以,默认情况下,我会让它 zero-allocation 与 API 的其余部分保持一致,但如果 consuming/end 开发人员可以接受垃圾并且想要那几个额外的纳秒,他们可以轻松允许。
我目前正在设计一个解决方案,并且发现自己处于一个有趣的性能场景中。我已经放置了一个非常简单的解决方案来演示可以在此处找到的这种情况:
https://github.com/Mike-EEE/Stash/tree/master/AllocationVsRent
这个问题的核心是阵列的分配与租赁。此解决方案中的一种方法执行租赁,如下所示:
[Benchmark]
public int Rented()
{
var array = _pool.Rent(2);
array[0] = 1;
array[1] = 2;
var result = array[0] + array[1];
_pool.Return(array);
return result;
}
另一个执行分配,如下所示:
[Benchmark(Baseline = true)]
public int Allocated()
{
var array = new int[2];
array[0] = 1;
array[1] = 2;
var result = array[0] + array[1];
return result;
}
当运行这两个基准时,我得到以下结果:
BenchmarkDotNet=v0.11.5, OS=Windows 10.0.17763.475 (1809/October2018Update/Redstone5)
AMD Ryzen 7 2700X, 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.0.100-preview5-011568
[Host] : .NET Core 3.0.0-preview5-27626-15 (CoreCLR 4.6.27622.75, CoreFX 4.700.19.22408), 64bit RyuJIT
DefaultJob : .NET Core 3.0.0-preview5-27626-15 (CoreCLR 4.6.27622.75, CoreFX 4.700.19.22408), 64bit RyuJIT
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------- |----------:|----------:|----------:|------:|--------:|-------:|------:|------:|----------:|
| Rented | 29.563 ns | 0.1736 ns | 0.1450 ns | 5.01 | 0.27 | - | - | - | - |
| Allocated | 5.825 ns | 0.1440 ns | 0.2522 ns | 1.00 | 0.00 | 0.0077 | - | - | 32 B |
虽然 Allocated
基准测试速度更快,但它确实调用了垃圾收集。而对于 Rented
基准测试,速度较慢但没有垃圾收集惩罚。
所以我的基本问题是:首选哪一个?即使它确实产生垃圾,也可以进行分配吗?虽然它更快,但我还是觉得它的使用很脏,请原谅双关语。
请注意:我不能使用stackalloc
,因为我的实践场景涉及两种方法之间的调用,据我所知,这排除了使用它的可能性。我当然愿意接受我忽略的任何建议,以便在这里获得两全其美。
提前感谢您的帮助。
由于我的场景涉及太多内容无法进一步解释(这里尽量保持简单),我通过允许最终开发人员决定他们是想要速度还是垃圾来解决这个问题。
关于更多上下文,我正在开发的 API 是 zero-allocation 首要的,速度是一个重要但次要的重点。
在所有其他调用中,API 是 zero-allocation 并且比我正在测试的现有 API 更快,但此调用除外。所以,默认情况下,我会让它 zero-allocation 与 API 的其余部分保持一致,但如果 consuming/end 开发人员可以接受垃圾并且想要那几个额外的纳秒,他们可以轻松允许。