在.net9中C#新的 Lock 对象

作者:微信公众号:【架构师老卢】
9-19 18:40
224

随着 .NET 9 的发布,最令人期待的功能之一是新对象。此新增功能引入了一种更灵活、更强大的机制,用于管理多线程应用程序中的同步。它通过提供更好的控制、改进的调试和更大的灵活性来增强传统的锁定方法。Lock

如何运作lock

该语句确保允许一个线程执行代码的关键部分,而其他尝试进入锁定部分的线程将被阻止,直到锁被释放。lock

当线程到达语句时,它会尝试获取给定对象的独占锁。如果没有其他线程持有该锁,则进入 critical 部分。如果另一个线程已经获取了锁,则当前线程将等待 (或阻塞) ,直到锁被释放。lock

下面是一个使用传统 :lock

namespace NewLock  
{  
    public class Account  
    {  
        private readonly object _lockObject = new();  
        private decimal _balance;  
  
        public void Deposit(decimal amount)  
        {  
            // Acquire the lock  
            lock (_lockObject)  
            {  
                _balance += amount;  
            }  
        }  
    }  
}

在幕后,该方法用于获取锁,并具有回退机制来确保锁被释放:Monitor.Enter

namespace NewLock
{
  public class Account
  {
    [Nullable(1)]
    private readonly object _lockObject;
    private Decimal _balance;

    public void Deposit(Decimal amount)
    {
      //This line assigns the _lockObject to a local variable lockObject. This step ensures that the same lock object is used throughout the locking process.
      object lockObject = this._lockObject;
      
      //A bool variable lockTaken is initialized to false. This flag is used to track whether the lock was successfully acquired.
      bool lockTaken = false;
      try
      {
        //This line is where the actual locking happens. Monitor.Enter is the method that acquires an exclusive lock on the lockObject.         
        Monitor.Enter(lockObject, ref lockTaken);
        this._balance = Decimal.op_Addition(this._balance, amount);
      }
      finally
      {
        if (lockTaken)
          Monitor.Exit(lockObject);
      }
    }

    public Account()
    {
      this._lockObject = new object();
      base..ctor();
    }
  }
}

使用新对象Lock

在 .NET 9 中,新对象提供了对锁定的更多控制:Lock

namespace NewLock
{
    public class Account
    {
        private readonly Lock _lockObject = new();
        private decimal _balance;

        public void Deposit(decimal amount)
        {
            // Acquire the lock
            lock (_lockObject)
            {
                _balance += amount;
            }
        }
    }
}

在后台,该对象处理获取和释放锁。这可确保通过该方法安全地释放锁,即使在出现异常的情况下也是如此。Lock.ScopeDispose()

namespace NewLock
{
  public class Account
  {
    [Nullable(1)]
    private readonly Lock _lockObject;
    private Decimal _balance;

    public void Deposit(Decimal amount)
    {
      //The EnterScope method of the Lock object is called to acquire a lock on the critical section (in this case, updating the balance)
      Lock.Scope scope = this._lockObject.EnterScope();
      try
      {
        this._balance = Decimal.op_Addition(this._balance, amount);
      }
      finally
      {
        //Releasing the Lock
        scope.Dispose();
      }
    }

    public Account()
    {
      this._lockObject = new Lock();
      base..ctor();
    }
  }
}

对传统锁与新锁进行基准测试

以下设置对传统与新的性能进行了基准测试:lockLock

namespace NewLock
{
    public class AccountBenchmarks
    {
        private const decimal Amount = 100m;
        private const int TaskCount = 1000;
        private const int OperationsPerTask = 1000;

        // Traditional lock-based account
        public class TraditionalAccount
        {
            private readonly object _lockObject = new();
            private decimal _balance;

            public void Deposit(decimal amount)
            {
                lock (_lockObject)
                {
                    _balance += amount;
                }
            }

            public decimal GetBalance() => _balance;
        }

        // New Lock-based account (from .NET 9)
        public class NewLockAccount
        {
            private readonly Lock _lockObject = new();
            private decimal _balance;

            public void Deposit(decimal amount)
            {
                using (var scope = _lockObject.EnterScope())
                {
                    _balance += amount;
                }
            }

            public decimal GetBalance() => _balance;
        }

        // Test method for traditional lock
        [Benchmark]
        public decimal TestTraditionalLock()
        {
            var account = new TraditionalAccount();
            Parallel.For(0, TaskCount, _ =>
            {
                for (int i = 0; i < OperationsPerTask; i++)
                {
                    account.Deposit(Amount);
                }
            });

            return account.GetBalance();
        }

        // Test method for new Lock object
        [Benchmark]
        public decimal TestNewLock()
        {
            var account = new NewLockAccount();
            Parallel.For(0, TaskCount, _ =>
            {
                for (int i = 0; i < OperationsPerTask; i++)
                {
                    account.Deposit(Amount);
                }
            });

            return account.GetBalance();
        }
    }
}

.NET 9 中的新对象以最小的内存开销提供更高的性能,使其成为高性能、线程安全应用程序的理想选择。

相关留言评论
昵称:
邮箱:
阅读排行