Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.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
F#NativePtr.stackalloc比C#stackalloc慢-包含反编译代码_C#_F#_Stack_Unmanaged Memory - Fatal编程技术网

F#NativePtr.stackalloc比C#stackalloc慢-包含反编译代码

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

继续我的F#性能测试。有关更多背景信息,请参见此处:

现在我有了在F#中工作的堆栈数组。然而,由于某种原因,等效的C#大约快50倍。我已经在下面列出了ILSpy反编译版本,看起来只有一行是真正不同的(在stackAlloc内部)

这是怎么回事?未经检查的算法真的要为这一巨大差异负责吗?不知道我怎么能测试这个

F#代码

#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  
这个练习教会了我一些东西:

  • 编译器执行大量优化。显然,不同语言中相同的高级代码可以产生完全不同的机器指令集
  • 在对dotnet语言进行基准测试时,您可以阅读中间程序集来真正了解情况。使用ILSpy进行此操作
  • 可以使用ilasm.exe修改和编译中间程序集
  • C#编译器在删除不必要的代码方面做得更好。一旦您在分配的内存中设置了每个字节,性能就会与最初预期的非常相似
  • 最终F#代码

    #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倍。