From 98ded1d26c630781ddab15ebee817ca5e0d61964 Mon Sep 17 00:00:00 2001 From: Frank Dong Date: Thu, 12 Dec 2019 15:34:09 -0800 Subject: [PATCH 1/4] fix issue 4528, use thread safe ConcurrentDictionary instead of Dictionary which is not thread safe in read/write mode --- src/Microsoft.Extensions.ML/PredictionEnginePool.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Extensions.ML/PredictionEnginePool.cs b/src/Microsoft.Extensions.ML/PredictionEnginePool.cs index 57b7637286..6a1de4ee78 100644 --- a/src/Microsoft.Extensions.ML/PredictionEnginePool.cs +++ b/src/Microsoft.Extensions.ML/PredictionEnginePool.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Concurrent; using System.Collections.Generic; using Microsoft.Extensions.Options; using Microsoft.ML; @@ -21,7 +22,7 @@ public class PredictionEnginePool private readonly IOptionsFactory> _predictionEngineOptions; private readonly IServiceProvider _serviceProvider; private readonly PoolLoader _defaultEnginePool; - private readonly Dictionary> _namedPools; + private readonly ConcurrentDictionary> _namedPools; public PredictionEnginePool(IServiceProvider serviceProvider, IOptions mlContextOptions, @@ -38,7 +39,7 @@ public PredictionEnginePool(IServiceProvider serviceProvider, _defaultEnginePool = new PoolLoader(_serviceProvider, defaultOptions); } - _namedPools = new Dictionary>(); + _namedPools = new ConcurrentDictionary>(); } /// @@ -100,7 +101,7 @@ public PredictionEngine GetPredictionEngine(string modelName //Here we are in the world of named models where the model hasn't been built yet. var options = _predictionEngineOptions.Create(modelName); var pool = new PoolLoader(_serviceProvider, options); - _namedPools.Add(modelName, pool); + _namedPools.TryAdd(modelName, pool); return pool.PredictionEnginePool.Get(); } From 5c2b3ec3a9d692c61e6dcbee3a1a652d00dce454 Mon Sep 17 00:00:00 2001 From: Frank Dong Date: Thu, 12 Dec 2019 16:37:39 -0800 Subject: [PATCH 2/4] take comments and fix --- src/Microsoft.Extensions.ML/PredictionEnginePool.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Extensions.ML/PredictionEnginePool.cs b/src/Microsoft.Extensions.ML/PredictionEnginePool.cs index 6a1de4ee78..bdaf8dd01f 100644 --- a/src/Microsoft.Extensions.ML/PredictionEnginePool.cs +++ b/src/Microsoft.Extensions.ML/PredictionEnginePool.cs @@ -80,9 +80,11 @@ public PredictionEngine GetPredictionEngine() /// public PredictionEngine GetPredictionEngine(string modelName) { - if (_namedPools.ContainsKey(modelName)) + PoolLoader existingPool = null; + _namedPools.TryGetValue(modelName, out existingPool); + if (_namedPools.TryGetValue(modelName, out existingPool)) { - return _namedPools[modelName].PredictionEnginePool.Get(); + return existingPool.PredictionEnginePool.Get(); } //This is the case where someone has used string.Empty to get the default model. @@ -101,7 +103,7 @@ public PredictionEngine GetPredictionEngine(string modelName //Here we are in the world of named models where the model hasn't been built yet. var options = _predictionEngineOptions.Create(modelName); var pool = new PoolLoader(_serviceProvider, options); - _namedPools.TryAdd(modelName, pool); + pool = _namedPools.GetOrAdd(modelName, pool); return pool.PredictionEnginePool.Get(); } From 02cbe683224987bffda5ccb34cb27280707d2d5e Mon Sep 17 00:00:00 2001 From: Frank Dong Date: Thu, 12 Dec 2019 16:39:18 -0800 Subject: [PATCH 3/4] remove unnecessary code --- src/Microsoft.Extensions.ML/PredictionEnginePool.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.Extensions.ML/PredictionEnginePool.cs b/src/Microsoft.Extensions.ML/PredictionEnginePool.cs index bdaf8dd01f..a4bb561b72 100644 --- a/src/Microsoft.Extensions.ML/PredictionEnginePool.cs +++ b/src/Microsoft.Extensions.ML/PredictionEnginePool.cs @@ -81,7 +81,6 @@ public PredictionEngine GetPredictionEngine() public PredictionEngine GetPredictionEngine(string modelName) { PoolLoader existingPool = null; - _namedPools.TryGetValue(modelName, out existingPool); if (_namedPools.TryGetValue(modelName, out existingPool)) { return existingPool.PredictionEnginePool.Get(); From 89e740b3a43b1a9a67c2c95bb0e345f61c23042e Mon Sep 17 00:00:00 2001 From: Frank Dong Date: Thu, 12 Dec 2019 16:46:14 -0800 Subject: [PATCH 4/4] simplify out variables --- src/Microsoft.Extensions.ML/PredictionEnginePool.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Microsoft.Extensions.ML/PredictionEnginePool.cs b/src/Microsoft.Extensions.ML/PredictionEnginePool.cs index a4bb561b72..6c15289bb5 100644 --- a/src/Microsoft.Extensions.ML/PredictionEnginePool.cs +++ b/src/Microsoft.Extensions.ML/PredictionEnginePool.cs @@ -80,8 +80,7 @@ public PredictionEngine GetPredictionEngine() /// public PredictionEngine GetPredictionEngine(string modelName) { - PoolLoader existingPool = null; - if (_namedPools.TryGetValue(modelName, out existingPool)) + if (_namedPools.TryGetValue(modelName, out var existingPool)) { return existingPool.PredictionEnginePool.Get(); }