From 996347aa7d77bb8684da075148950f9dc6d47c5c Mon Sep 17 00:00:00 2001 From: IgnatSergeev Date: Sat, 1 Jun 2024 01:09:35 +0300 Subject: [PATCH 1/2] Finished --- F#/Lazy.Test/Lazy.Test.fsproj | 29 +++++++++++++++ F#/Lazy.Test/LazyTest.fs | 67 +++++++++++++++++++++++++++++++++++ F#/Lazy/ILazy.fs | 4 +++ F#/Lazy/Lazy.fsproj | 15 ++++++++ F#/Lazy/LockFreeLazy.fs | 10 ++++++ F#/Lazy/MultiThreadedLazy.fs | 13 +++++++ F#/Lazy/SingleThreadedLazy.fs | 9 +++++ F#/forSpbu.sln | 12 +++++++ 8 files changed, 159 insertions(+) create mode 100644 F#/Lazy.Test/Lazy.Test.fsproj create mode 100644 F#/Lazy.Test/LazyTest.fs create mode 100644 F#/Lazy/ILazy.fs create mode 100644 F#/Lazy/Lazy.fsproj create mode 100644 F#/Lazy/LockFreeLazy.fs create mode 100644 F#/Lazy/MultiThreadedLazy.fs create mode 100644 F#/Lazy/SingleThreadedLazy.fs diff --git a/F#/Lazy.Test/Lazy.Test.fsproj b/F#/Lazy.Test/Lazy.Test.fsproj new file mode 100644 index 0000000..4b4c995 --- /dev/null +++ b/F#/Lazy.Test/Lazy.Test.fsproj @@ -0,0 +1,29 @@ + + + + net8.0 + + false + true + true + + + + + + + + + + + + + + + + + + + + + diff --git a/F#/Lazy.Test/LazyTest.fs b/F#/Lazy.Test/LazyTest.fs new file mode 100644 index 0000000..a744f1e --- /dev/null +++ b/F#/Lazy.Test/LazyTest.fs @@ -0,0 +1,67 @@ +module Lazy.Test + +open NUnit.Framework +open FsUnit + +type Counter () = + let mutable callCounter = 0 + member this.Increment () = + System.Threading.Interlocked.Increment(&callCounter) + member this.Counter = callCounter + +let lazyImplementations = + [ + (fun func -> S.Lazy func :> ILazy.ILazy) + (fun func -> M.Lazy func) + (fun func -> LF.Lazy func) + ] |> List.map (fun x -> TestCaseData(x)) + +[] +[] +let getTest (genLazy) = + let l : ILazy.ILazy = genLazy (fun () -> 1) + l.Get() |> should equal 1 + +[] +let singleThreadCountTest () = + let counter = Counter() + let l : ILazy.ILazy = S.Lazy(counter.Increment) + l.Get() |> ignore + l.Get() |> ignore + l.Get() |> ignore + counter.Counter |> should equal 1 + +[] +let simpleMultiThrCountTest () = + let counter = Counter() + let l : ILazy.ILazy = M.Lazy(counter.Increment) + l.Get() |> ignore + l.Get() |> ignore + l.Get() |> ignore + counter.Counter |> should equal 1 + +[] +let complexMultiThrCountTest () = + let counter = Counter() + let l : ILazy.ILazy = M.Lazy(counter.Increment) + let getTask = task { return l.Get() } + let results = (fun _ -> getTask |> Async.AwaitTask) |> Seq.initInfinite |> Seq.take 10 |> Async.Parallel |> Async.RunSynchronously + counter.Counter |> should equal 1 + Seq.iter (fun x -> (x = (Seq.last results)) |> should equal true) results + +[] +let simpleLockFreeTest () = + let counter = Counter() + let l : ILazy.ILazy = LF.Lazy(counter.Increment) + l.Get() |> ignore + l.Get() |> ignore + l.Get() |> ignore + counter.Counter |> should equal 1 + +[] +let complexLockFreeTest () = + let counter = Counter() + let l : ILazy.ILazy = LF.Lazy(counter.Increment) + let getTask = task { return l.Get() } + let results = (fun _ -> getTask |> Async.AwaitTask) |> Seq.initInfinite |> Seq.take 10 |> Async.Parallel |> Async.RunSynchronously + Seq.iter (fun x -> (x = (Seq.last results)) |> should equal true) results diff --git a/F#/Lazy/ILazy.fs b/F#/Lazy/ILazy.fs new file mode 100644 index 0000000..446a581 --- /dev/null +++ b/F#/Lazy/ILazy.fs @@ -0,0 +1,4 @@ +module Lazy.ILazy + +type ILazy<'a> = + abstract member Get: unit -> 'a diff --git a/F#/Lazy/Lazy.fsproj b/F#/Lazy/Lazy.fsproj new file mode 100644 index 0000000..03d5967 --- /dev/null +++ b/F#/Lazy/Lazy.fsproj @@ -0,0 +1,15 @@ + + + + net8.0 + true + + + + + + + + + + diff --git a/F#/Lazy/LockFreeLazy.fs b/F#/Lazy/LockFreeLazy.fs new file mode 100644 index 0000000..5fd36a3 --- /dev/null +++ b/F#/Lazy/LockFreeLazy.fs @@ -0,0 +1,10 @@ +module Lazy.LF + +type Lazy<'a>(func) = + let mutable value : Option<'a> = None + interface ILazy.ILazy<'a> with + member this.Get() = + if value.IsNone then + let localValue = func() + System.Threading.Interlocked.CompareExchange(&value, Some(localValue), None) |> ignore + value.Value diff --git a/F#/Lazy/MultiThreadedLazy.fs b/F#/Lazy/MultiThreadedLazy.fs new file mode 100644 index 0000000..038b6ba --- /dev/null +++ b/F#/Lazy/MultiThreadedLazy.fs @@ -0,0 +1,13 @@ +module Lazy.M + +type Lazy<'a>(func) = + let mutable value : Option<'a> = None + let valueLock = obj + interface ILazy.ILazy<'a> with + member this.Get() = + if value.IsNone then + lock valueLock (fun () -> + if value.IsNone then + value <- Some(func()) + ) + value.Value diff --git a/F#/Lazy/SingleThreadedLazy.fs b/F#/Lazy/SingleThreadedLazy.fs new file mode 100644 index 0000000..2390bde --- /dev/null +++ b/F#/Lazy/SingleThreadedLazy.fs @@ -0,0 +1,9 @@ +module Lazy.S + +type Lazy<'a>(f) = + let mutable value : Option<'a> = None + interface ILazy.ILazy<'a> with + member this.Get() = + if value.IsNone then + value <- Some(f()) + value.Value diff --git a/F#/forSpbu.sln b/F#/forSpbu.sln index 9d54d03..b38709a 100644 --- a/F#/forSpbu.sln +++ b/F#/forSpbu.sln @@ -21,6 +21,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "07.03", "07.03", "{5CA9053B EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Homework1", "Homework1\Homework1.fsproj", "{04B15EE4-079A-42ED-ACC8-E2DCD25281C6}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Lazy", "Lazy\Lazy.fsproj", "{31761996-9105-4FCD-A2BE-87F64952A72A}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Lazy.Test", "Lazy.Test\Lazy.Test.fsproj", "{F290B1F9-5753-4585-881D-25641368A803}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -58,6 +62,14 @@ Global {89A935E8-B5F3-435D-ACC3-A99DD7C66178}.Debug|Any CPU.Build.0 = Debug|Any CPU {89A935E8-B5F3-435D-ACC3-A99DD7C66178}.Release|Any CPU.ActiveCfg = Release|Any CPU {89A935E8-B5F3-435D-ACC3-A99DD7C66178}.Release|Any CPU.Build.0 = Release|Any CPU + {31761996-9105-4FCD-A2BE-87F64952A72A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {31761996-9105-4FCD-A2BE-87F64952A72A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {31761996-9105-4FCD-A2BE-87F64952A72A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {31761996-9105-4FCD-A2BE-87F64952A72A}.Release|Any CPU.Build.0 = Release|Any CPU + {F290B1F9-5753-4585-881D-25641368A803}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F290B1F9-5753-4585-881D-25641368A803}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F290B1F9-5753-4585-881D-25641368A803}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F290B1F9-5753-4585-881D-25641368A803}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {7937CDA8-8285-4E23-AD1A-FC0F04FEEFE6} = {91E3BDA2-0836-46C2-95F0-02513FD7F13F} From c85341391190f0ac7cafbdc0adc5b886ecce8aab Mon Sep 17 00:00:00 2001 From: IgnatSergeev Date: Sat, 1 Jun 2024 01:13:34 +0300 Subject: [PATCH 2/2] Added comments --- F#/Lazy/ILazy.fs | 8 ++++++++ F#/Lazy/LockFreeLazy.fs | 4 ++++ F#/Lazy/MultiThreadedLazy.fs | 4 ++++ F#/Lazy/SingleThreadedLazy.fs | 4 ++++ 4 files changed, 20 insertions(+) diff --git a/F#/Lazy/ILazy.fs b/F#/Lazy/ILazy.fs index 446a581..ed49d25 100644 --- a/F#/Lazy/ILazy.fs +++ b/F#/Lazy/ILazy.fs @@ -1,4 +1,12 @@ module Lazy.ILazy +/// +/// Interface for lazy function calculation +/// +/// Function return value type ILazy<'a> = + /// + /// Lazily calculates given function + /// + /// Function result abstract member Get: unit -> 'a diff --git a/F#/Lazy/LockFreeLazy.fs b/F#/Lazy/LockFreeLazy.fs index 5fd36a3..821e2c6 100644 --- a/F#/Lazy/LockFreeLazy.fs +++ b/F#/Lazy/LockFreeLazy.fs @@ -1,5 +1,9 @@ module Lazy.LF +/// +/// Lock free multi threaded implementation of iLazy interface +/// +/// Result type type Lazy<'a>(func) = let mutable value : Option<'a> = None interface ILazy.ILazy<'a> with diff --git a/F#/Lazy/MultiThreadedLazy.fs b/F#/Lazy/MultiThreadedLazy.fs index 038b6ba..5065ccf 100644 --- a/F#/Lazy/MultiThreadedLazy.fs +++ b/F#/Lazy/MultiThreadedLazy.fs @@ -1,5 +1,9 @@ module Lazy.M +/// +/// Multi threaded implementation of iLazy interface +/// +/// Result type type Lazy<'a>(func) = let mutable value : Option<'a> = None let valueLock = obj diff --git a/F#/Lazy/SingleThreadedLazy.fs b/F#/Lazy/SingleThreadedLazy.fs index 2390bde..2cc1f15 100644 --- a/F#/Lazy/SingleThreadedLazy.fs +++ b/F#/Lazy/SingleThreadedLazy.fs @@ -1,5 +1,9 @@ module Lazy.S +/// +/// Single threaded implementation of iLazy interface +/// +/// Result type type Lazy<'a>(f) = let mutable value : Option<'a> = None interface ILazy.ILazy<'a> with