4 votes

Le bloc d'application de mise en cache de la bibliothèque Microsoft Enterprise n'est pas sûr pour les threads ?

J'ai créé une application console très simple pour tester le bloc d'application de mise en cache de la bibliothèque d'entreprise, et le comportement est déconcertant. J'espère que j'ai foiré quelque chose de facile à corriger dans l'installation. J'ai fait en sorte que chaque élément expire au bout de 5 secondes à des fins de test.

Configuration de base -- "Toutes les secondes, choisissez un nombre entre 0 et 2. Si le cache ne l'a pas déjà, mettez-le dedans -- sinon prenez-le dans le cache. Faites ceci à l'intérieur d'une instruction LOCK pour assurer la sécurité des threads.

APP.CONFIG :

<configuration>
  <configSections>
    <section name="cachingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Caching.Configuration.CacheManagerSettings, Microsoft.Practices.EnterpriseLibrary.Caching, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </configSections>
  <cachingConfiguration defaultCacheManager="Cache Manager">
    <cacheManagers>
      <add expirationPollFrequencyInSeconds="1" maximumElementsInCacheBeforeScavenging="1000"
      numberToRemoveWhenScavenging="10" backingStoreName="Null Storage"
      type="Microsoft.Practices.EnterpriseLibrary.Caching.CacheManager, Microsoft.Practices.EnterpriseLibrary.Caching, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
      name="Cache Manager" />
    </cacheManagers>
    <backingStores>
      <add encryptionProviderName="" type="Microsoft.Practices.EnterpriseLibrary.Caching.BackingStoreImplementations.NullBackingStore, Microsoft.Practices.EnterpriseLibrary.Caching, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
      name="Null Storage" />
    </backingStores>
  </cachingConfiguration>
</configuration>

C# :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Common;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;

namespace ConsoleApplication1
{
    class Program
    {
        public static ICacheManager cache = CacheFactory.GetCacheManager("Cache Manager");
    static void Main(string[] args)
        {
            while (true)
            {
                System.Threading.Thread.Sleep(1000); // sleep for one second.
                var key = new Random().Next(3).ToString();
                string value;
                lock (cache)
                {
                    if (!cache.Contains(key))
                    {
                        cache.Add(key, key, CacheItemPriority.Normal, null, new SlidingTime(TimeSpan.FromSeconds(5)));
                    }
                    value = (string)cache.GetData(key);
                }
                Console.WriteLine("{0} --> '{1}'", key, value);
                //if (null == value) throw new Exception(); 
            }
        }
    }
}

OUTPUT -- Comment empêcher le cache de renvoyer des nullités ?

2 --> '2'
1 --> '1'
2 --> '2'
0 --> '0'
2 --> '2'
0 --> '0'
1 --> ''
0 --> '0'
1 --> '1'
2 --> ''
0 --> '0'
2 --> '2'
0 --> '0'
1 --> ''
2 --> '2'
1 --> '1'
Press any key to continue . . .

0voto

Chris Gessler Points 11887

Je sais que cette question est assez ancienne, mais le problème est que vous utilisez Contains puis en essayant de récupérer la valeur. Dans l'intervalle de temps Contains y GetData ont été appelés, l'article a expiré et a été supprimé. GetData a renvoyé un résultat nul. C'est ce que l'on appelle une condition de course.

La solution est assez simple (sans utiliser de verrous), ne pas utiliser de Contains

private static void CachingBlockTest()
{
    while (true)
    {
        System.Threading.Thread.Sleep(2000);

        var key = new Random().Next(3).ToString();
        string value = cache.GetData(key) as string;

        if (value == null)
        {
            value = key;
            cache.Add(key, value, CacheItemPriority.Normal, new RefreshAction(),
                new SlidingTime(TimeSpan.FromSeconds(5)));
        }
        Console.WriteLine("{0} --> '{1}'", key, value);
    } 
}
private class RefreshAction : ICacheItemRefreshAction
{
    public void Refresh(string removedKey, object expiredValue, CacheItemRemovedReason removalReason)
    {
        Console.WriteLine("{0} --> {1} removed", removedKey, expiredValue);
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X