-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added IDisposable support for several classes #4939
Changes from 8 commits
1b871b6
e18ec7e
2d5a186
98f5a10
c0fa246
07ef104
3c96cad
f12d5d3
60e8238
34fa8d5
98647ca
65c3297
cb96929
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using Microsoft.ML; | ||
using Microsoft.ML.Data; | ||
using Microsoft.ML.Runtime; | ||
|
@@ -15,7 +16,7 @@ namespace Microsoft.ML.Data | |
/// This class represents a data loader that applies a transformer chain after loading. | ||
/// It also has methods to save itself to a repository. | ||
/// </summary> | ||
public sealed class CompositeDataLoader<TSource, TLastTransformer> : IDataLoader<TSource> | ||
public sealed class CompositeDataLoader<TSource, TLastTransformer> : IDataLoader<TSource>, IDisposable | ||
where TLastTransformer : class, ITransformer | ||
{ | ||
internal const string TransformerDirectory = TransformerChain.LoaderSignature; | ||
|
@@ -38,13 +39,15 @@ public CompositeDataLoader(IDataLoader<TSource> loader, TransformerChain<TLastTr | |
|
||
Loader = loader; | ||
Transformer = transformerChain ?? new TransformerChain<TLastTransformer>(); | ||
_disposed = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
private CompositeDataLoader(IHost host, ModelLoadContext ctx) | ||
{ | ||
if (!ctx.LoadModelOrNull<IDataLoader<TSource>, SignatureLoadModel>(host, out Loader, LegacyLoaderDirectory)) | ||
ctx.LoadModel<IDataLoader<TSource>, SignatureLoadModel>(host, out Loader, LoaderDirectory); | ||
ctx.LoadModel<TransformerChain<TLastTransformer>, SignatureLoadModel>(host, out Transformer, TransformerDirectory); | ||
_disposed = false; | ||
} | ||
|
||
private static CompositeDataLoader<TSource, TLastTransformer> Create(IHostEnvironment env, ModelLoadContext ctx) | ||
|
@@ -110,5 +113,25 @@ private static VersionInfo GetVersionInfo() | |
loaderSignature: LoaderSignature, | ||
loaderAssemblyName: typeof(CompositeDataLoader<,>).Assembly.FullName); | ||
} | ||
|
||
#region IDisposable Support | ||
private bool _disposed; | ||
|
||
private void Dispose(bool disposing) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 This is the legacy There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Weren't there two cases to be handled before? The one that calls Dispose(true) from from IDisposable.Dispose() and the other that calls Dispose(false) from the finalizer? (Or someplace else...I am not quite sure). How would that be handled? In reply to: 396132625 [](ancestors = 396132625) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Finalizers are not allowed under the new dispose pattern. Since there are no finalizers, there are no calls to |
||
{ | ||
if (_disposed) | ||
return; | ||
|
||
if (disposing) | ||
Transformer.Dispose(); | ||
|
||
_disposed = true; | ||
} | ||
|
||
void IDisposable.Dispose() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you explicitly implementing The reason to not explicitly implement an interface is so users of the class can just call |
||
{ | ||
Dispose(true); | ||
} | ||
#endregion | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📝 By making the class disposable when
IDataLoader<TSource>
is not disposable, it will be easy for a consumer to fail to dispose of the object. #ResolvedThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't change interfaces now that they are shipped. Right now, when customers discover they have a memory leak, we don't have a solution. With this method at least we can tell them to add a Dispose call.
Is there a better approach we can consider?
In reply to: 396132696 [](ancestors = 396132696)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every case that I reviewed locally required breaking API changes. Default interface methods might be an option for .NET Core targets, but those are completely unsupported on .NET Framework. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the component GA? Or can we still make a breaking change? #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All public interfaces are frozen. This would be one of those.
In reply to: 396753025 [](ancestors = 396753025)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There may be a difference between interfaces released as GA and the preview releases. I'm not sure which one this falls under.
/cc @eerhardt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IDataLoader is a core interface. It is part of the GA set.
In reply to: 396760924 [](ancestors = 396760924)