F#NativePtr.stackalloc比C#stackalloc慢-包含反编译代码
继续我的F#性能测试。有关更多背景信息,请参见此处: 现在我有了在F#中工作的堆栈数组。然而,由于某种原因,等效的C#大约快50倍。我已经在下面列出了ILSpy反编译版本,看起来只有一行是真正不同的(在stackAlloc内部) 这是怎么回事?未经检查的算法真的要为这一巨大差异负责吗?不知道我怎么能测试这个 F#代码F#NativePtr.stackalloc比C#stackalloc慢-包含反编译代码,c#,f#,stack,unmanaged-memory,C#,F#,Stack,Unmanaged Memory,继续我的F#性能测试。有关更多背景信息,请参见此处: 现在我有了在F#中工作的堆栈数组。然而,由于某种原因,等效的C#大约快50倍。我已经在下面列出了ILSpy反编译版本,看起来只有一行是真正不同的(在stackAlloc内部) 这是怎么回事?未经检查的算法真的要为这一巨大差异负责吗?不知道我怎么能测试这个 F#代码 #nowarn "9" open Microsoft.FSharp.NativeInterop open System open System.Diagnostics
#nowarn "9"
open Microsoft.FSharp.NativeInterop
open System
open System.Diagnostics
open System.Runtime.CompilerServices
[<MethodImpl(MethodImplOptions.NoInlining)>]
let stackAlloc x =
let mutable ints:nativeptr<byte> = NativePtr.stackalloc x
()
[<EntryPoint>]
let main argv =
printfn "%A" argv
let size = 8192
let reps = 10000
stackAlloc size // JIT
let clock = Stopwatch()
clock.Start()
for i = 1 to reps do
stackAlloc size
clock.Stop()
let elapsed = clock.Elapsed.TotalMilliseconds
let description = "F# NativePtr.stackalloc"
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed)
Console.ReadKey() |> ignore
0
using System;
using System.Diagnostics;
namespace CSharpLanguageFeatures
{
class CSharpStackArray
{
static void Main(string[] args)
{
int size = 8192;
int reps = 10000;
stackAlloc(size); // JIT
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 0; i < reps; i++)
{
stackAlloc(size);
}
clock.Stop();
string elapsed = clock.Elapsed.TotalMilliseconds.ToString("#,##0.####");
string description = "C# stackalloc";
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed);
Console.ReadKey();
}
public unsafe static void stackAlloc(int arraySize)
{
byte* pArr = stackalloc byte[arraySize];
}
}
}
#nowarn "9"
open Microsoft.FSharp.NativeInterop
open System
open System.Diagnostics
open System.Runtime.CompilerServices
[<MethodImpl(MethodImplOptions.NoInlining)>]
let stackAlloc x =
let mutable bytes:nativeptr<byte> = NativePtr.stackalloc x
for i = 0 to (x - 1) do
NativePtr.set bytes i (byte i)
()
[<EntryPoint>]
let main argv =
printfn "%A" argv
let size = 8192
let reps = 10000
stackAlloc size // JIT
let clock = Stopwatch()
clock.Start()
for i = 1 to reps do
stackAlloc size
clock.Stop()
let elapsed = clock.Elapsed.TotalMilliseconds
let description = "F# NativePtr.stackalloc"
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed)
Console.ReadKey() |> ignore
0
using System;
using System.Diagnostics;
namespace CSharpStackArray
{
class Program
{
static void Main(string[] args)
{
int size = 8192;
int reps = 10000;
stackAlloc(size); // JIT
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 0; i < reps; i++)
{
stackAlloc(size);
}
clock.Stop();
string elapsed = clock.Elapsed.TotalMilliseconds.ToString("#,##0.####");
string description = "C# stackalloc";
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed);
Console.ReadKey();
}
public unsafe static void stackAlloc(int arraySize)
{
byte* pArr = stackalloc byte[arraySize];
for (int i = 0; i < arraySize; i++)
{
pArr[i] = (byte)i;
}
}
}
}
C#版本IL-字节分配
.method public static
void stackAlloc (
int32 x
) cil managed noinlining
{
// Method begins at RVA 0x2050
// Code size 13 (0xd)
.maxstack 4
.locals init (
[0] native int ints
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: sizeof [mscorlib]System.Byte
IL_0008: mul
IL_0009: localloc
IL_000b: stloc.0
IL_000c: ret
} // end of method FSharpStackArray::stackAlloc
.method public hidebysig static
void stackAlloc (
int32 arraySize
) cil managed
{
// Method begins at RVA 0x2094
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: conv.u
IL_0002: ldc.i4.1
IL_0003: mul.ovf.un
IL_0004: localloc
IL_0006: pop
IL_0007: ret
} // end of method CSharpStackArray::stackAlloc
.method public static
void stackAlloc (
int32 x
) cil managed noinlining
{
// Method begins at RVA 0x2050
// Code size 13 (0xd)
.maxstack 4
.locals init (
[0] native int ints
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: sizeof [mscorlib]System.IntPtr
IL_0008: mul
IL_0009: localloc
IL_000b: stloc.0
IL_000c: ret
} // end of method FSharpStackArray::stackAlloc
.method public hidebysig static
void stackAlloc (
int32 arraySize
) cil managed
{
// Method begins at RVA 0x2415
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.0
IL_0001: conv.u
IL_0002: sizeof [mscorlib]System.IntPtr
IL_0008: mul.ovf.un
IL_0009: localloc
IL_000b: pop
IL_000c: ret
} // end of method CSharpStackArray::stackAlloc
更新了F#IL-IntPtr分配
.method public static
void stackAlloc (
int32 x
) cil managed noinlining
{
// Method begins at RVA 0x2050
// Code size 13 (0xd)
.maxstack 4
.locals init (
[0] native int ints
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: sizeof [mscorlib]System.Byte
IL_0008: mul
IL_0009: localloc
IL_000b: stloc.0
IL_000c: ret
} // end of method FSharpStackArray::stackAlloc
.method public hidebysig static
void stackAlloc (
int32 arraySize
) cil managed
{
// Method begins at RVA 0x2094
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: conv.u
IL_0002: ldc.i4.1
IL_0003: mul.ovf.un
IL_0004: localloc
IL_0006: pop
IL_0007: ret
} // end of method CSharpStackArray::stackAlloc
.method public static
void stackAlloc (
int32 x
) cil managed noinlining
{
// Method begins at RVA 0x2050
// Code size 13 (0xd)
.maxstack 4
.locals init (
[0] native int ints
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: sizeof [mscorlib]System.IntPtr
IL_0008: mul
IL_0009: localloc
IL_000b: stloc.0
IL_000c: ret
} // end of method FSharpStackArray::stackAlloc
.method public hidebysig static
void stackAlloc (
int32 arraySize
) cil managed
{
// Method begins at RVA 0x2415
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.0
IL_0001: conv.u
IL_0002: sizeof [mscorlib]System.IntPtr
IL_0008: mul.ovf.un
IL_0009: localloc
IL_000b: pop
IL_000c: ret
} // end of method CSharpStackArray::stackAlloc
更新的C#IL-IntPtr分配
.method public static
void stackAlloc (
int32 x
) cil managed noinlining
{
// Method begins at RVA 0x2050
// Code size 13 (0xd)
.maxstack 4
.locals init (
[0] native int ints
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: sizeof [mscorlib]System.Byte
IL_0008: mul
IL_0009: localloc
IL_000b: stloc.0
IL_000c: ret
} // end of method FSharpStackArray::stackAlloc
.method public hidebysig static
void stackAlloc (
int32 arraySize
) cil managed
{
// Method begins at RVA 0x2094
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: conv.u
IL_0002: ldc.i4.1
IL_0003: mul.ovf.un
IL_0004: localloc
IL_0006: pop
IL_0007: ret
} // end of method CSharpStackArray::stackAlloc
.method public static
void stackAlloc (
int32 x
) cil managed noinlining
{
// Method begins at RVA 0x2050
// Code size 13 (0xd)
.maxstack 4
.locals init (
[0] native int ints
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: sizeof [mscorlib]System.IntPtr
IL_0008: mul
IL_0009: localloc
IL_000b: stloc.0
IL_000c: ret
} // end of method FSharpStackArray::stackAlloc
.method public hidebysig static
void stackAlloc (
int32 arraySize
) cil managed
{
// Method begins at RVA 0x2415
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.0
IL_0001: conv.u
IL_0002: sizeof [mscorlib]System.IntPtr
IL_0008: mul.ovf.un
IL_0009: localloc
IL_000b: pop
IL_000c: ret
} // end of method CSharpStackArray::stackAlloc
谢谢大家在这方面的帮助 答案是C#编译器没有将指针存储为本地指针。这是因为不需要分配的内存。缺少“sizeof”和不同的“mul”给了C#另一个微弱的优势 F#汇编程序-对差异进行注释
using Microsoft.FSharp.Core;
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
[CompilationMapping(SourceConstructFlags.Module)]
public static class FSharpStackArray
{
[MethodImpl(MethodImplOptions.NoInlining)]
public unsafe static void stackAlloc(int x)
{
IntPtr ints = stackalloc byte[x * sizeof(byte)];
}
[EntryPoint]
public static int main(string[] argv)
{
PrintfFormat<FSharpFunc<string[], Unit>, TextWriter, Unit, Unit> format = new PrintfFormat<FSharpFunc<string[], Unit>, TextWriter, Unit, Unit, string[]>("%A");
PrintfModule.PrintFormatLineToTextWriter<FSharpFunc<string[], Unit>>(Console.Out, format).Invoke(argv);
FSharpStackArray.stackAlloc(8192);
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 1; i < 10001; i++)
{
FSharpStackArray.stackAlloc(8192);
}
clock.Stop();
double elapsed = clock.Elapsed.TotalMilliseconds;
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", "F# NativePtr.stackalloc", 8192, 10000, elapsed);
ConsoleKeyInfo consoleKeyInfo = Console.ReadKey();
return 0;
}
}
using System;
using System.Diagnostics;
namespace CSharpLanguageFeatures
{
internal class CSharpStackArray
{
private static void Main(string[] args)
{
int size = 8192;
int reps = 10000;
CSharpStackArray.stackAlloc(size);
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 0; i < reps; i++)
{
CSharpStackArray.stackAlloc(size);
}
clock.Stop();
string elapsed = clock.Elapsed.TotalMilliseconds.ToString("#,##0.####");
string description = "C# stackalloc";
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", new object[]
{
description,
size,
reps,
elapsed
});
Console.ReadKey();
}
public unsafe static void stackAlloc(int arraySize)
{
IntPtr arg_06_0 = stackalloc byte[checked(unchecked((UIntPtr)arraySize) * 1)];
}
}
}
.method public static
void stackAlloc (
int32 x
) cil managed noinlining
{
// Method begins at RVA 0x2050
// Code size 13 (0xd)
.maxstack 4
.locals init ( //***** Not in C# Version *****//
[0] native int ints
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: sizeof [mscorlib]System.Byte //***** C# just uses "1" *****//
IL_0008: mul //***** C# uses "mul.ovf.un" *****//
IL_0009: localloc
IL_000b: stloc.0 //***** Not in C# Version *****//
IL_000c: ret
} // end of method FSharpStackArray::stackAlloc
.method public hidebysig static
void stackAlloc (
int32 arraySize
) cil managed
{
// Method begins at RVA 0x2094
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: conv.u
IL_0002: ldc.i4.1 //***** F# uses sizeof [mscorlib]System.Byte *****//
IL_0003: mul.ovf.un //***** F# uses "mul" *****//
IL_0004: localloc
IL_0006: pop
IL_0007: ret
} // end of method CSharpStackArray::stackAlloc
C#汇编程序-对差异进行注释
using Microsoft.FSharp.Core;
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
[CompilationMapping(SourceConstructFlags.Module)]
public static class FSharpStackArray
{
[MethodImpl(MethodImplOptions.NoInlining)]
public unsafe static void stackAlloc(int x)
{
IntPtr ints = stackalloc byte[x * sizeof(byte)];
}
[EntryPoint]
public static int main(string[] argv)
{
PrintfFormat<FSharpFunc<string[], Unit>, TextWriter, Unit, Unit> format = new PrintfFormat<FSharpFunc<string[], Unit>, TextWriter, Unit, Unit, string[]>("%A");
PrintfModule.PrintFormatLineToTextWriter<FSharpFunc<string[], Unit>>(Console.Out, format).Invoke(argv);
FSharpStackArray.stackAlloc(8192);
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 1; i < 10001; i++)
{
FSharpStackArray.stackAlloc(8192);
}
clock.Stop();
double elapsed = clock.Elapsed.TotalMilliseconds;
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", "F# NativePtr.stackalloc", 8192, 10000, elapsed);
ConsoleKeyInfo consoleKeyInfo = Console.ReadKey();
return 0;
}
}
using System;
using System.Diagnostics;
namespace CSharpLanguageFeatures
{
internal class CSharpStackArray
{
private static void Main(string[] args)
{
int size = 8192;
int reps = 10000;
CSharpStackArray.stackAlloc(size);
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 0; i < reps; i++)
{
CSharpStackArray.stackAlloc(size);
}
clock.Stop();
string elapsed = clock.Elapsed.TotalMilliseconds.ToString("#,##0.####");
string description = "C# stackalloc";
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", new object[]
{
description,
size,
reps,
elapsed
});
Console.ReadKey();
}
public unsafe static void stackAlloc(int arraySize)
{
IntPtr arg_06_0 = stackalloc byte[checked(unchecked((UIntPtr)arraySize) * 1)];
}
}
}
.method public static
void stackAlloc (
int32 x
) cil managed noinlining
{
// Method begins at RVA 0x2050
// Code size 13 (0xd)
.maxstack 4
.locals init ( //***** Not in C# Version *****//
[0] native int ints
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: sizeof [mscorlib]System.Byte //***** C# just uses "1" *****//
IL_0008: mul //***** C# uses "mul.ovf.un" *****//
IL_0009: localloc
IL_000b: stloc.0 //***** Not in C# Version *****//
IL_000c: ret
} // end of method FSharpStackArray::stackAlloc
.method public hidebysig static
void stackAlloc (
int32 arraySize
) cil managed
{
// Method begins at RVA 0x2094
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: conv.u
IL_0002: ldc.i4.1 //***** F# uses sizeof [mscorlib]System.Byte *****//
IL_0003: mul.ovf.un //***** F# uses "mul" *****//
IL_0004: localloc
IL_0006: pop
IL_0007: ret
} // end of method CSharpStackArray::stackAlloc
这个练习教会了我一些东西:
#nowarn "9"
open Microsoft.FSharp.NativeInterop
open System
open System.Diagnostics
open System.Runtime.CompilerServices
[<MethodImpl(MethodImplOptions.NoInlining)>]
let stackAlloc x =
let mutable ints:nativeptr<byte> = NativePtr.stackalloc x
()
[<EntryPoint>]
let main argv =
printfn "%A" argv
let size = 8192
let reps = 10000
stackAlloc size // JIT
let clock = Stopwatch()
clock.Start()
for i = 1 to reps do
stackAlloc size
clock.Stop()
let elapsed = clock.Elapsed.TotalMilliseconds
let description = "F# NativePtr.stackalloc"
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed)
Console.ReadKey() |> ignore
0
using System;
using System.Diagnostics;
namespace CSharpLanguageFeatures
{
class CSharpStackArray
{
static void Main(string[] args)
{
int size = 8192;
int reps = 10000;
stackAlloc(size); // JIT
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 0; i < reps; i++)
{
stackAlloc(size);
}
clock.Stop();
string elapsed = clock.Elapsed.TotalMilliseconds.ToString("#,##0.####");
string description = "C# stackalloc";
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed);
Console.ReadKey();
}
public unsafe static void stackAlloc(int arraySize)
{
byte* pArr = stackalloc byte[arraySize];
}
}
}
#nowarn "9"
open Microsoft.FSharp.NativeInterop
open System
open System.Diagnostics
open System.Runtime.CompilerServices
[<MethodImpl(MethodImplOptions.NoInlining)>]
let stackAlloc x =
let mutable bytes:nativeptr<byte> = NativePtr.stackalloc x
for i = 0 to (x - 1) do
NativePtr.set bytes i (byte i)
()
[<EntryPoint>]
let main argv =
printfn "%A" argv
let size = 8192
let reps = 10000
stackAlloc size // JIT
let clock = Stopwatch()
clock.Start()
for i = 1 to reps do
stackAlloc size
clock.Stop()
let elapsed = clock.Elapsed.TotalMilliseconds
let description = "F# NativePtr.stackalloc"
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed)
Console.ReadKey() |> ignore
0
using System;
using System.Diagnostics;
namespace CSharpStackArray
{
class Program
{
static void Main(string[] args)
{
int size = 8192;
int reps = 10000;
stackAlloc(size); // JIT
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 0; i < reps; i++)
{
stackAlloc(size);
}
clock.Stop();
string elapsed = clock.Elapsed.TotalMilliseconds.ToString("#,##0.####");
string description = "C# stackalloc";
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed);
Console.ReadKey();
}
public unsafe static void stackAlloc(int arraySize)
{
byte* pArr = stackalloc byte[arraySize];
for (int i = 0; i < arraySize; i++)
{
pArr[i] = (byte)i;
}
}
}
}
\nowarn“9”
打开Microsoft.FSharp.NativeInterop
开放系统
开放系统诊断
open System.Runtime.CompilerServices
[]
让stackAlloc x=
让可变字节:nativeptr=nativeptr.stackalloc x
对于i=0到(x-1)do
NativePtr.set字节i(字节i)
()
[]
让主argv=
printfn“%A”argv
let size=8192
让重复次数=10000
stackAlloc大小//JIT
让时钟=秒表
时钟开始
对于i=1的重复次数
stackAlloc尺寸
时钟停止
let appeased=clock.appeased.total毫秒
let description=“F#NativePtr.stackalloc”
WriteLine(“{0}({1}字节,{2}个代表):{3:#,##############ms”,描述,大小,代表,已用时间)
Console.ReadKey()|>忽略
0
最终C#代码
#nowarn "9"
open Microsoft.FSharp.NativeInterop
open System
open System.Diagnostics
open System.Runtime.CompilerServices
[<MethodImpl(MethodImplOptions.NoInlining)>]
let stackAlloc x =
let mutable ints:nativeptr<byte> = NativePtr.stackalloc x
()
[<EntryPoint>]
let main argv =
printfn "%A" argv
let size = 8192
let reps = 10000
stackAlloc size // JIT
let clock = Stopwatch()
clock.Start()
for i = 1 to reps do
stackAlloc size
clock.Stop()
let elapsed = clock.Elapsed.TotalMilliseconds
let description = "F# NativePtr.stackalloc"
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed)
Console.ReadKey() |> ignore
0
using System;
using System.Diagnostics;
namespace CSharpLanguageFeatures
{
class CSharpStackArray
{
static void Main(string[] args)
{
int size = 8192;
int reps = 10000;
stackAlloc(size); // JIT
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 0; i < reps; i++)
{
stackAlloc(size);
}
clock.Stop();
string elapsed = clock.Elapsed.TotalMilliseconds.ToString("#,##0.####");
string description = "C# stackalloc";
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed);
Console.ReadKey();
}
public unsafe static void stackAlloc(int arraySize)
{
byte* pArr = stackalloc byte[arraySize];
}
}
}
#nowarn "9"
open Microsoft.FSharp.NativeInterop
open System
open System.Diagnostics
open System.Runtime.CompilerServices
[<MethodImpl(MethodImplOptions.NoInlining)>]
let stackAlloc x =
let mutable bytes:nativeptr<byte> = NativePtr.stackalloc x
for i = 0 to (x - 1) do
NativePtr.set bytes i (byte i)
()
[<EntryPoint>]
let main argv =
printfn "%A" argv
let size = 8192
let reps = 10000
stackAlloc size // JIT
let clock = Stopwatch()
clock.Start()
for i = 1 to reps do
stackAlloc size
clock.Stop()
let elapsed = clock.Elapsed.TotalMilliseconds
let description = "F# NativePtr.stackalloc"
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed)
Console.ReadKey() |> ignore
0
using System;
using System.Diagnostics;
namespace CSharpStackArray
{
class Program
{
static void Main(string[] args)
{
int size = 8192;
int reps = 10000;
stackAlloc(size); // JIT
Stopwatch clock = new Stopwatch();
clock.Start();
for (int i = 0; i < reps; i++)
{
stackAlloc(size);
}
clock.Stop();
string elapsed = clock.Elapsed.TotalMilliseconds.ToString("#,##0.####");
string description = "C# stackalloc";
Console.WriteLine("{0} ({1} bytes, {2} reps): {3:#,##0.####}ms", description, size, reps, elapsed);
Console.ReadKey();
}
public unsafe static void stackAlloc(int arraySize)
{
byte* pArr = stackalloc byte[arraySize];
for (int i = 0; i < arraySize; i++)
{
pArr[i] = (byte)i;
}
}
}
}
使用系统;
使用系统诊断;
命名空间CSharpStackArray
{
班级计划
{
静态void Main(字符串[]参数)
{
int size=8192;
int reps=10000;
stackAlloc(大小);//JIT
秒表时钟=新秒表();
clock.Start();
对于(int i=0;i
您能否显示这两种方法的实际IL?嗯,可能是[mscorlib]System.Byte或nop的大小?循环中还有一个nop?sizeof
肯定起到了一定的作用,但我认为更重要的是mul
。请尝试在不同的体系结构上使用不同的类型,例如intptr
本身。似乎C#编译器通过使用sizeof(byte)
总是1
这一知识来优化此计算。更改为IntPtr分配会使C#版本的计算时间比原来长约2倍。它使F#版本的时间比原来长10倍。