【问题标题】:Problems using static MemcachedClient使用静态 MemcachedClient 的问题
【发布时间】:2016-10-19 13:15:42
【问题描述】:

我正在使用 Memcached 存储数据以便快速访问。我读过创建 MemcachedClient 的成本很高,并且看到 MemcachedClient 的使用是静态的(请参阅:link

所以我为我的客户使用了单例模式:

public class CommonObjectsCache
{
    private static CommonObjectsCache _cache;
    private static MemcachedClient _client;

    public static MemcachedClient Client
    {
        get
        {
            if (_client == null)
                _client = new MemcachedClient();

            return _client;
        }
        private set
        {
            _client = value;
        }
    }

    private CommonObjectsCache()
    {
        _client = new MemcachedClient();
    }

    public static CommonObjectsCache Cache
    {
        get
        {
            if (_cache == null)
                _cache = new CommonObjectsCache();

            return _cache;
        }
    }
}

在我的 DAL 中,我按如下方式使用它们:

    public static List<Item1> AllItem1s
    {
        get
        {
            if (CommonObjectsCache.Client.Get<List<Item1>>("AllItem1s") == null)
                RefreshItem1Cache();

            return CommonObjectsCache.Client.Get<List<Item1>>("AllItem1s");
        }
        private set
        {
            CommonObjectsCache.Client.Store(StoreMode.Set, "AllItem1s", value);
        }
    }
    public static List<Item2> AllItem2s
    {
        get {  // Same as above }
        private set { // Same as above }
    }
    public static List<Item3> AllItem3s
    {
        get {  // Same as above }
        private set { // Same as above }
    }
    public static List<Item4> AllItem4s
    {
        get {  // Same as above }
        private set { // Same as above }

    }

并将它们填写为:

public static void RefreshItem1Cache()
{
    List<Item1> items = (from i ctx.Item1
                        select i).ToList();
    AllItem1s = items;
}

在我的 DAL 代码中,我有一个类似的方法:

public static MyModel GetMyModel(int? id)
{
    // I use AllItem1s here.
}

当我运行代码时,它有时会显示AllItem1s.Count == 0,但是当我在 AllItem1s 中放置断点并诊断该值时,我看到它已被填充。因此,我将代码更新如下,以检查我是否做错了:

public static MyModel GetMyModel(int? id)
{
    if (AllItem1s == null || AllItem1s.Count == 0 || AllItem2s == null || AllItem2s.Count == 0 || AllItem3s == null || AllItem3s.Count == 0 || AllItem4s == null || AllItem4s.Count == 0)
    {
        string msg = "Error!!!!!";
    }
    // I use AllItem1s here.
}

令人惊讶的是,代码落入string msg = "Error!!!!!";块!!!

但是当我在 if 块内放置一个断点并观察每个集合的 Count 属性时,我发现它们有数字。

所以我得出结论,在获取AllItemXs 属性时存在竞争条件。当它检查条件时,其中至少有一个没有被正确设置(这没有意义,因为它们在同一个线程上,并且属性的 getter 不能返回空集合)。

谁能解释为什么会发生这种情况以及如何克服这个问题?

【问题讨论】:

  • RefreshItem1Cache();方法是什么样的? CommonObjectsCache.Client 设置器是否在某处使用? RefreshGroupCache() 用在什么地方?
  • 你能显示SearchItem1s的代码吗?
  • 这些是普通的 EF 调用。我已经更新了代码。
  • 所以你从来没有真正使用过CommonObjectsCache.Cache

标签: c# asp.net-mvc memcached


【解决方案1】:

您的单例实现不是线程安全的。 想象一下,两个(或更多)线程同时进行空值检查:两个(所有)线程都将初始化它们自己的 CommonObjectsCache 实例。

您可以使用 lock 语句包装空值检查和实例初始化或使用双重检查锁定模式。

只需 google 一下 C# 中的线程安全单例实现即可。

【讨论】:

    猜你喜欢
    • 2017-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-17
    相关资源
    最近更新 更多