#!/usr/bin/env-Sdotnetfsi--mlcompatibility--optimize--warnaserror+:25,26(* This construct is for ML compatibility. The syntax '(typ,...,typ) ident'
is not used in F# code. Consider using 'ident<typ,...,typ>' instead. *)#nowarn"62"[<RequireQualifiedAccess>]moduleGarbageCollection=(* Swapping type-safety for high performance using compiler directives:
- https://fsharpforfunandprofit.com/posts
/typesafe-performance-with-compiler-directives
/#timing-the-two-implementations
*)openSystemletinlineresetn=matchnwith|None->GC.Collect()|Somev->GC.CollectvGC.WaitForPendingFinalizers()letinlinegen00()=GC.CollectionCount0letinlinegen01()=GC.CollectionCount1letinlinegen02()=GC.CollectionCount2letinlinemem()=GC.GetTotalMemoryfalseletinlineprint()=sprintf"GC gen0: %i, gen1: %i, gen2: %i, mem: %i bytes."(gen00())(gen01())(gen02())(mem())[<RequireQualifiedAccess>]modulePerformance=(* C#: Is this benchmarking class accurate?
- https://stackoverflow.com/a/1508597
*)openSystem.Diagnosticsletinlinetimef=leth=Stopwatch.IsHighResolutionletw=Stopwatch()letinlinestart_=w.Restart()letinlinestop_=w.Stop();w.Elapsed.TotalSecondsGarbageCollection.resetNoneletstruct(bg0,bg1,bg2,bm)=struct(GarbageCollection.gen00(),GarbageCollection.gen01(),GarbageCollection.gen02(),GarbageCollection.mem())let_=start()let_=f()lets=stop()letstruct(ag0,ag1,ag2,am)=struct(GarbageCollection.gen00(),GarbageCollection.gen01(),GarbageCollection.gen02(),GarbageCollection.mem())GarbageCollection.resetNonesprintf"hf: %b, time: %9f, GC gen0: %i, gen1: %i, gen2: %i, mem: %i."hs(ag0-bg0)(ag1-bg1)(ag2-bg2)(am-bm)[<RequireQualifiedAccess>]moduleThread=openSystem.Threadingtype[<Struct>]'at={state:'astateref;thread:thread}and[<Struct>]'astate=privateSof'aoptionand[<Struct>]thread=privateTofThreadletinlineforkf=letaux(g:unit->unit)=lett=Threadgt.IsBackground<-truet.Start()tlets=ref(SNone)letinlineh()=s:=(S(Some(f()))){state=s;thread=T(auxh)}letinlinejoin{state=sr;thread=(Tt)}=t.Join()let(Sso)=!srOption.getsoletinlinemtid{thread=(Tt)}=t.ManagedThreadId[<RequireQualifiedAccess>]moduleUtil=letinlinecores_=System.Environment.ProcessorCountletinlinesleepn=Thread.Sleep(millisecondsTimeout=n)[<RequireQualifiedAccess>]modulePool=[<RequireQualifiedAccess>]moduleAtomic=letinlineinc(i:intref)=Interlocked.Incrementiletinlinemaptsfa=(* Inspired by "F# for Scientists" by Jon Harrop (978-0470242117)
but using an atomic increment (interlocked) for the index counter
*)letn=Array.lengthaletb=Array.createnNoneleti=ref-1letrecappj=ifj<nthenb.[j]<-Some(fa.[j]);aux()andaux_=app(Atomic.inci)Array.initts(fun_->forkaux)|>Array.iterjoinArray.chooseidblet_=letinlinefi=Thread.Util.sleep1;(+)1printfn"# Sequential"printfn"## f i = Thread.Util.sleep 1; (+) 1"printfn"## Array.create 10_000 0 |> Array.map f"fun___->Array.create10_0000|>Array.mapf|>Performance.time|>printfn"%s"let_=letc=Thread.Util.cores()letinlinefi=Thread.Util.sleep1;(+)1printfn"# Concurrent"printfn"## c = Thread.Util.cores ()"printfn"%i"cprintfn"## f i = Thread.Util.sleep 1; (+) 1"printfn"## Array.create 10_000 0 |> Thread.Pool.map c f"fun___->Array.create10_0000|>Thread.Pool.mapcf|>Performance.time|>printfn"%s"