c# - 为什么在我的 asp.net 代码中多次创建我的静态对象?

标签 c# windbg stackexchange.redis

我认为静态对象是跨多个线程共享的。然而,我的一个站点出现了高 CPU 问题,所以我进行了 windbg 转储,非常惊讶,我看到了这个:

enter image description here

我们可以看到有 10 个名为 ConnectionMultiplexer 的类的实例。但是我的代码将 ConnectionMultiplexer 创建为静态对象。这应该意味着只为所有线程创建一个实例。那么 windbg 为何显示多个实例?

这是我创建redis连接的代码

public static class CacheConnection
    {
        private static StackExchangeRedisCacheClient _newconnectionDb;

        public static StackExchangeRedisCacheClient NewConnectionDb
            => _newconnectionDb ?? (_newconnectionDb = NewRedisConnection());

        private static IDatabase _connectionDb;

        public static IDatabase ConnectionDb => _connectionDb ?? (_connectionDb = RedisConnection());

        private static StackExchangeRedisCacheClient NewRedisConnection()
        {
            var serializer = new NewtonsoftSerializer();
            return new StackExchangeRedisCacheClient(Connection, serializer);
        }

        private static IDatabase RedisConnection()
        {
            var cacheDatabase = Connection.GetDatabase();
            return cacheDatabase;
        }

        public static ConnectionMultiplexer Connection => LazyConnection.Value;

        private static readonly Lazy<ConnectionMultiplexer> LazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(
            System.Configuration.ConfigurationManager.AppSettings["CacheConnectionString"]), LazyThreadSafetyMode.PublicationOnly);
    }

最佳答案

ConnectionMultiplexer 实际上是一个使用新的 C# 7 短语法 => 的只读(获取)属性,它会在您每次访问它时返回 LazyConnection.Value

然后你使用 LazyThreadSafetyMode.PublicationOnly 在 MSDN ( https://msdn.microsoft.com/en-us/library/system.threading.lazythreadsafetymode(v=vs.110).aspx ) 中这样定义

When multiple threads try to initialize a Lazy instance simultaneously, all threads are allowed to run the initialization method (or the default constructor, if there is no initialization method). The first thread to complete initialization sets the value of the Lazy instance. That value is returned to any other threads that were simultaneously running the initialization method, unless the initialization method throws exceptions on those threads. Any instances of T that were created by the competing threads are discarded. If the initialization method throws an exception on any thread, the exception is propagated out of the Lazy.Value property on that thread. The exception is not cached. The value of the IsValueCreated property remains false, and subsequent calls to the Value property, either by the thread where the exception was thrown or by other threads, cause the initialization method to run again. If the initialization method recursively accesses the Value property of the Lazy instance, no exception is thrown.

这意味着如果多个线程同时尝试访问它,它们将各自创建自己的实例,尽管您最终会使用第一个创建的实例,而不管线程如何(但实例仍然存在)。

你真正需要的是LazyThreadSafetyMode.ExecutionAndPublication 但这可能会引入死锁。

如果您不需要将其设置为 Lazy,则可以使用 Jon Skeet 在他的《C# 深入》一书中建议的单例模式实现之一

您可以在这里找到它们 http://csharpindepth.com/Articles/General/Singleton.aspx

关于c# - 为什么在我的 asp.net 代码中多次创建我的静态对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46472433/

相关文章:

c# - 如何制作更好的落 block ?

qt - 即使根本没有代码,QT应用程序也会崩溃

c# - 从 Redis 检索多个键时死锁

debugging - 什么是 mdToken?它与 MethodTable 有何不同?

redis - Redis 键过期时间的上限和下限

lua - Redis Lua 脚本相对于键空间通知是原子的?

c# - 单声道下的 ICSharpCode?

c# - 错误 : 'Subscript indices must either be real positive integers or logicals' when using Matlab . NET 生成器

c# - 在另一个列表中添加列表项

.net - 将所有字符串类型的值从托管堆转储到文件 - WinDbg