เหตุใดวัตถุคงที่ของฉันจึงถูกสร้างขึ้นหลายครั้งในรหัส asp.net ของฉัน

ฉันคิดว่าวัตถุคงที่ถูกแชร์ผ่านหลายเธรด อย่างไรก็ตาม ฉันประสบปัญหา CPU สูงบนเว็บไซต์หนึ่งของฉัน ดังนั้นฉันจึงทำการถ่ายโอนข้อมูล windbg และประหลาดใจมาก ฉันเห็นสิ่งนี้:

ป้อนคำอธิบายรูปภาพที่นี่

เราจะเห็นได้ว่ามี 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);
    }

person daxu    schedule 28.09.2017    source แหล่งที่มา
comment
เกี่ยวกับประโยคแรกของคุณ: วัตถุใดๆ ก็ตามอยู่บนฮีป และฮีปนั้นสามารถใช้ได้กับเธรดใดๆ ดังนั้นความจริงที่ว่ามันคงที่จึงไม่สำคัญ   -  person Thomas Weller    schedule 28.09.2017


คำตอบ (1)


จริงๆ แล้ว ConnectionMultiplexer เป็นคุณสมบัติแบบอ่านอย่างเดียว (รับ) โดยใช้ไวยากรณ์สั้น C# 7 ใหม่ => ที่ส่งคืน LazyConnection.Value ทุกครั้งที่คุณเข้าถึง

จากนั้นคุณใช้ LazyThreadSafetyMode.PublicationOnly ซึ่งกำหนดไว้เช่นนี้ใน MSDN (https://msdn.microsoft.com/en-us/library/system.threading.lazythreadsafetymode(v=vs.110).aspx)

เมื่อหลายเธรดพยายามเริ่มต้นอินสแตนซ์ Lazy พร้อมกัน เธรดทั้งหมดจะได้รับอนุญาตให้เรียกใช้วิธีการเริ่มต้น (หรือตัวสร้างเริ่มต้น หากไม่มีวิธีการเริ่มต้น) เธรดแรกที่ดำเนินการเริ่มต้นให้เสร็จสมบูรณ์จะตั้งค่าของอินสแตนซ์ Lazy ค่านั้นจะถูกส่งกลับไปยังเธรดอื่น ๆ ที่กำลังเรียกใช้วิธีการเตรียมใช้งานพร้อมกัน เว้นแต่ว่าวิธีการเตรียมใช้งานจะแสดงข้อยกเว้นบนเธรดเหล่านั้น อินสแตนซ์ใดๆ ของ T ที่สร้างขึ้นโดยเธรดที่แข่งขันกันจะถูกละทิ้ง หากวิธีการเริ่มต้นส่งข้อยกเว้นบนเธรดใด ๆ ข้อยกเว้นจะถูกเผยแพร่ออกจากคุณสมบัติ Lazy.Value บนเธรดนั้น ข้อยกเว้นไม่ได้ถูกแคชไว้ ค่าของคุณสมบัติ IsValueCreated ยังคงเป็นเท็จ และการเรียกคุณสมบัติ Value ในเวลาต่อมา ไม่ว่าจะโดยเธรดที่มีข้อยกเว้นเกิดขึ้นหรือโดยเธรดอื่น จะทำให้วิธีการเตรียมใช้งานทำงานอีกครั้ง หากวิธีการเริ่มต้นเข้าถึงคุณสมบัติ Value ของอินสแตนซ์ Lazy แบบวนซ้ำ จะไม่มีข้อยกเว้นเกิดขึ้น

ซึ่งหมายความว่าหากหลายเธรดพยายามเข้าถึงในเวลาเดียวกัน แต่ละเธรดจะสร้างอินสแตนซ์ของตัวเอง แม้ว่าคุณจะใช้เธรดแรกที่สร้างขึ้นโดยไม่คำนึงถึงเธรด (แต่อินสแตนซ์ยังคงอยู่ตรงนั้น)

สิ่งที่คุณต้องการจริงๆ คือ LazyThreadSafetyMode.ExecutionAndPublication แต่อาจทำให้เกิดการหยุดชะงักได้

หากคุณไม่ต้องการให้เป็น Lazy คุณสามารถใช้หนึ่งในการใช้งานรูปแบบซิงเกิลตันที่แนะนำโดย Jon Skeet ในหนังสือของเขา C# In Depth

คุณสามารถค้นหาได้ที่นี่ http://csharpin allowance.com/Articles/General/Singleton.aspx

person Mihail Shishkov    schedule 28.09.2017