Performance Optimization

BenchmarkDotNet, dotnet-trace, dotnet-counters, PerfView, Rider/VS profilers Choose collections wisely

Arrays and ResizeArray/Dictionary for hot paths; avoid @ in loops; avoid repeated List.item

Struct tuples (struct (a, b)), struct records/unions, ValueOption, [<InlineIfLambda>]

Inline small generic functions to avoid boxing and enable specialization

Slice without copying; stackalloc via NativePtr.stackalloc Seq vs List/Array

Seq has per-element overhead; materialize hot data Tail recursion and loops

Avoid deep non-tail recursion on large inputs Mutable locals inside functions Fine for performance when encapsulated

task { } over async { } in hot I/O paths Custom [<CustomEquality>] or [<ReferenceEquality>] when structural equality is expensive StringBuilder, String.concat Release builds, ReadyToRun, Native AOT

dotnet publish -c Release -p:PublishReadyToRun=true / -p:PublishAot=true (check library compatibility)

#r "nuget: BenchmarkDotNet"
open BenchmarkDotNet.Attributes
open BenchmarkDotNet.Running

[<MemoryDiagnoser>]
type ListVsArray() =
    let data = [| 1 .. 10_000 |]
    let list = List.ofArray data
    [<Benchmark>] member _.ListSum() = List.sum list
    [<Benchmark>] member _.ArraySum() = Array.sum data
    [<Benchmark>] member _.SeqSum() = Seq.sum data
// BenchmarkRunner.Run<ListVsArray>() |> ignore   (run from a Release console app)

// [<InlineIfLambda>] lets the compiler inline lambda arguments
let inline iterFast ([<InlineIfLambda>] f: int -> unit) (arr: int[]) =
    for i in 0 .. arr.Length - 1 do f arr[i]