【问题标题】:How can I optimize read access?如何优化读取访问?
【发布时间】:2016-07-25 02:10:16
【问题描述】:

我处理主要是读取的数据,我希望尽可能高效地执行这些工作,并且我需要提供对它的线程安全访问。

欢迎对我的问题进行任何解释。谢谢

【问题讨论】:

    标签: c# multithreading performance entity-framework thread-safety


    【解决方案1】:

    那么创建线程的基础知识

    //
    Threat t = new Thread (My_Function);
    // or 
    Thread t = new Thread (()=>
    {
       //your code here
    });
    t.start();
    

    如果你想让读取线程安全,你可以在你想要确保串行访问的资源上使用“线程内的锁定语句”

    lock (Read_resource_object)
    {
    }
    

    lock 的作用是,代码第一次在 lock 语句上运行时,它将“锁定”资源,直到大括号的 then 为止。这不会阻止其他代码访问该对象,相反,如果任何其他代码调用该资源上的锁,则该代码会阻塞,直到锁定它的当前线程解锁它。当然要非常小心,以确保您没有获得线程锁,这通常发生在您的第一个锁内,代码流导致在解锁之前尝试锁定相同的代码。除此之外,我建议阅读一些关于这方面的教程,因为多线程和线程安全既困难又复杂!

    还有查找任务以及它们包装线程并提供附加功能。

    【讨论】:

      【解决方案2】:

      我在 C# 6 Cookbook 中找到了这个答案

      使用ReaderWriterLockSlim 提供多读/单写访问权限,并能够将锁从read 升级到write。例如,假设开发人员正在启动一个新项目。不幸的是,该项目人手不足,因此开发人员必须响应团队中许多其他人的任务。其他每个团队成员也会向开发人员询问他们任务的状态更新,有些甚至可以更改分配给开发人员的任务的优先级。开发人员通过AddTask 方法分配了一个任务。为了保护 Developer Tasks 集合,我们在 ReaderWriterLockSlim 上使用写锁,在将任务添加到 DeveloperTasks 集合时调用 EnterWrite Lock,在添加完成时调用 ExitWriteLock

      public void AddTask(DeveloperTask newTask)
      {
          try
          {
              Lock.EnterWriteLock();
              // if we already have this task (unique by name)        
              // then just accept the add as sometimes people        
              // give you the same task more than once :)        
              var taskQuery = from t in DeveloperTasks
                              where t == newTask
                              select t;
              if (taskQuery.Count<DeveloperTask>() == 0)
              {
                  Console.WriteLine($"Task {newTask.Name} was added to developer");
                  DeveloperTasks.Add(newTask);
              }
          }
          finally
          {
              Lock.ExitWriteLock();
          }
      }
      

      当项目团队成员需要了解任务的状态时,他们会调用IsTaskDone 方法,该方法通过调用EnterReadLockExitReadLockReaderWriterLockSlim 使用读锁:

      public bool IsTaskDone(string taskName)
      {
          try
          {
              Lock.EnterReadLock();
              var taskQuery = from t in DeveloperTasks
                              where t.Name == taskName
                              select t;
              if (taskQuery.Count<DeveloperTask>() > 0)
              {
                  DeveloperTask task = taskQuery.First<DeveloperTask>();
                  Console.WriteLine($"Task {task.Name} status was reported.");
                  return task.Status;
              }
          }
          finally
          {
              Lock.ExitReadLock();
          }
          return false;
      }
      

      团队中的某些管理成员有权提高他们分配给开发人员的任务的优先级。他们通过调用Developer 上的IncreasePriority 方法来实现这一点。 increasePriority 在ReaderWriterLockSlim 上使用可升级锁,首先调用EnterUpgradeable Lock 方法获取读锁,然后,如果任务在队列中,则升级为写锁以调整任务的优先级。调整好优先级后, 写锁被释放,这会将锁降级为读锁,并通过调用ExitUpgradeableReadLock来释放锁:

      public void IncreasePriority(string taskName)
      {
          try
          {
              Lock.EnterUpgradeableReadLock();
              var taskQuery = from t in DeveloperTasks
                              where t.Name == taskName
                              select t;
              if (taskQuery.Count<DeveloperTask>() > 0)
              {
                  DeveloperTask task = taskQuery.First<DeveloperTask>();
                  Lock.EnterWriteLock(); task.Priority++;
                  Console.WriteLine($"Task {task.Name}" + $" priority was increased to {task.Priority}" + " for developer"); Lock.ExitWriteLock();
              }
          }
          finally
          {
              Lock.ExitUpgradeableReadLock();
          }
      } 
      

      讨论创建ReaderWriterLockSlim 是为了替换现有的ReaderWriterLock,原因有很多:

      • ReaderWriterLock 比使用 监控。
      • ReaderWriterLock 的递归语义不是标准的,而是 在某些线程重入情况下被破坏。
      • 升级锁方法在 ReaderWriterLock 中是非原子的。虽然 ReaderWriterLockSlim 仅比 Monitor 慢两倍左右, 它更灵活并且优先考虑写入,因此在“少写多读”的场景中,它比Monitor更具可扩展性。
      • 还有一些方法可以确定持有哪种类型的锁 有多少线程正在等待获取它。默认情况下,lock 不允许获取递归。如果你调用 EnterReadLock 两次, 你得到一个LockRecursionException。您可以通过将 Lock RecusionPolicy.SupportsRecursion 枚举值传递给接受它的 ReaderWriterLockSlim 的构造函数重载来启用锁递归。
      • 尽管可以启用锁递归,但通常 气馁,因为它使事情复杂化并产生问题 调试起来不好玩。

      【讨论】:

        猜你喜欢
        • 2016-06-07
        • 1970-01-01
        • 1970-01-01
        • 2010-11-28
        • 1970-01-01
        • 2012-10-01
        • 2013-06-29
        • 2010-09-23
        • 1970-01-01
        相关资源
        最近更新 更多