Are F # observed events eliminating, mediating, or not related to the need for weak references?

Since observables are usually IDisposable , how will this change, if at all there is a need to use weak references in event handlers, or are any other event-based / GC memory leaks blocked by reference?

While my main problem / need is WPF, I am looking for a wider example and trying to figure out where I might need weak links.

F # Observable.add does not provide a way to cancel the event, so I think it is less likely to be a source of leaks. Code example:

 type Notifier() = let propChanged = new Event<_,_>() member __.Foo() = () interface INotifyPropertyChanged with [<CLIEvent>] member __.PropertyChanged = propChanged.Publish abstract member RaisePropertyChanged : string -> unit default x.RaisePropertyChanged(propertyName : string) = propChanged.Trigger(x, PropertyChangedEventArgs(propertyName)) Notifier() :?> INotifyPropertyChanged |> Observable.add(fun _ -> printfn "I'm hooked on you") 
+6
source share
1 answer

F # Observable.add does not provide a way to cancel the event, so I think it is less likely to be a source of leaks

In fact, the opposite is true. Observable.add , according to documents, constantly subscribes to an event and causes a "leak". It effectively performs the addition of an event handler that cannot unsubscribe.

In general, with Observable (in F # and C #), you should use .subscribe and manage your subscription descriptor when you're done.

As mentioned in @rmunn, Gjallarhorn can serve as an alternative to using observables in some scenarios (and if necessary combined with them). When writing it, one of my main goals was to ensure that subscriptions do not leak out - all subscriptions use a hybrid push / pull model, based on weak links, which prevents many problems with leakage in events and based on observable code.

To demonstrate, I chose a code variation using both observable and Gjallarhorn signals. If you run this in the release build, outside the debugger you will see the difference:

 type Notifier() = let propChanged = new Event<_,_>() member __.Foo() = () interface INotifyPropertyChanged with [<CLIEvent>] member __.PropertyChanged = propChanged.Publish abstract member RaisePropertyChanged : string -> unit default x.RaisePropertyChanged(propertyName : string) = propChanged.Trigger(x, PropertyChangedEventArgs(propertyName)) let obs () = use mre = new ManualResetEvent(false) let not = Notifier() do let inpc = not :> INotifyPropertyChanged inpc.PropertyChanged |> Observable.add (fun p -> printfn "Hit %s!" p.PropertyName) async { for i in [0 .. 10] do do! Async.Sleep 100 printfn "Raising" not.RaisePropertyChanged <| sprintf "%d" i mre.Set () |> ignore } |> Async.Start printfn "Exiting block" GC.Collect() // Force a collection, to "cleanup" mre.WaitOne() |> ignore let signals () = use mre = new ManualResetEvent(false) let not = Mutable.create 0 do not |> Signal.Subscription.create (fun v -> printfn "Hit %d!" v) |> ignore // throw away subscription handle async { for i in [0 .. 10] do do! Async.Sleep 100 printfn "Setting" not.Value <- i mre.Set () |> ignore } |> Async.Start printfn "Exiting block" GC.Collect() // Force a collection, to "cleanup" mre.WaitOne() |> ignore [<STAThread>] [<EntryPoint>] let main _ = printfn "Using observable" obs () printfn "Using signals" signals () 1 

Note that both do something similar - they create a "source", then subscribe to it in a separate area and throw out a one-time subscription subscriber ( Observable.add - this is nothing but subscribe |> ignore - see code for details. ) . When you run the release build outside the debugger (the debugger prevents cleaning), you see:

 Using observable Exiting block Raising Hit 0! Raising Hit 1! Raising Hit 2! Raising Hit 3! Raising Hit 4! Raising Hit 5! Raising Hit 6! Raising Hit 7! Raising Hit 8! Raising Hit 9! Raising Hit 10! Using signals Exiting block Setting Setting Setting Setting Setting Setting Setting Setting Setting Setting Setting Press any key to continue . . . 

In the observed case, the .add call constantly contains a link to the notifier, preventing it from collecting garbage. With signals, the subscription to the signal will be GC and will "unhook" automatically, preventing the display of calls from Hit.

+8
source

Source: https://habr.com/ru/post/1015217/


All Articles