【问题标题】:Optimized/Best way for reading/writing a shared resoruce读/写共享资源的优化/最佳方式
【发布时间】:2014-08-16 18:39:06
【问题描述】:

我的一个需求是管理共享资源(更像是一个日志,具有读写操作)

在应用程序中的不同进程(因此也是多个线程)之间。数据也应该是

坚持系统重启,因此它应该是一个物理文件/数据库。

共享资源是一些具有键、值信息的数据。 (因此可以使用此共享资源完成的可能操作是添加新的键值信息,

更新/删除现有的键值信息)。

因此我正在考虑使用 xml 文件来物理存储信息,示例内容将

看起来像,

<Root>
   <Key1>Value</Key1>
   <Key2>Value</Key2>
   <Key3>Value</Key3>
</Root>

进行读取和操作的界面如下所示,

    public interface IDataHandler
    {
       IDictionary<string,string> GetData();
       void SetData(string key,string value);
    }

我可以假设数据不会超过 500 MB,因此 xml 决定以及数据是否增长 我会将其移至数据库。 此外,与读取操作相比,写入数据会更多。

与上述场景相关的查询/设计考虑很少,

这样可以处理 xml 文件中的 500 MB 数据吗?

假设文件为 xml ,现在如何处理性能考虑?

  • 我正在考虑将数据缓存(.Net 中的MemoryCache 类)为 Dictionary ,这将启用

为了达到读操作时的性能,是否可以在内存中缓存 500 MB 的数据,或者我们是否可以

还有其他选择吗?

  • 现在,如果我使用上面的缓存机制,写操作过程中会发生什么:

  • 我是否应该在每次写入操作期间通过转换

  • 将字典内容再次写入 xml

整个字典到 xml ?要么 - 有什么方法可以只更新 xml 文件中数据被修改/添加的部分?或任何

处理这种情况的其他方法? - 我是否应该通过将写入操作放入队列和后台来再次提高性能

线程读取队列并启用实际写入操作,以便实际写入数据的人

不会因为写入文件而受到影响吗? - 处理多线程场景,打算用全局名的Mutex,有没有其他的

更好的方法?

我确定,我的操作几乎没有假设,并尝试从那里构建,如果我错了

某些假设会改变大部分设计概念。因此,全新的解决方案也是

欢迎(以绩效为主要标准)。 提前致谢。

【问题讨论】:

  • 这一切听起来都非常复杂且容易出错。为什么不使用数据库?数据库解决诸如持久性、一致性、崩溃一致性、备份、高可用性等问题。
  • 我会保留它作为一个选项,而不是直接考虑数据库,我还想了解其他选项的优缺点,因此从 xml/text 文件开始。如果您觉得这种基于文件的方法容易出错,请您多解释一下如何解释,至少正如我所料,这对我来说是一个新的学习。
  • @usr: 忘了提一下,开始时 xml 大小不会超过 1MB 左右,但随着时间的推移会像几年后一样小幅增长。我不想在初始阶段本身投资 DB 解决方案,但必须保持我的设计开放以在未来支持它。你仍然认为我在做/假设有什么问题吗?
  • 好吧,我提到的所有问题你都得有答案。这需要时间并且容易出错。例如,如果您在编写新的数据库版本时进程死机(错误、蓝屏、断电)怎么办?现在你有一半的数据库。其余的都没了。你可以安全地完成这项工作,但为什么要承担这个负担呢?您还谈到了线程和排队。你正在进入那里的危险领域。作为一个学习项目,这是可以的,但对于商业项目,这是错误的解决方案。选择一种易于施工且安全的。
  • 使用XML文件有什么特殊原因吗?

标签: c# multithreading performance optimization file-io


【解决方案1】:

正如你所说的“写操作多于读”,我假设数据增长得更快,所以我的建议是开始为数据库设计。它不需要像 MSSQL 或 MYSQL 这样的全功能数据库,您可以从 SQL-Lite 或 MSSQL-Compact 开始。这使您的应用程序在未来证明了大数据处理能力。

存储大量读取数据(例如在 RAM 中不会发生太大变化的配置)是一种有效的方法。我的建议是使用一些缓存管理器,例如 MemoryCache 或 Enterprise Library Caching Block,这样可以节省大量时间来实现 线程安全 数据访问和噩梦 :) 而不是自己编写。

public interface IDataHandler
{
   IDictionary<string,string> GetData();
   void SetData(string key,string value);
}

public class MyDataHandler : IDataHandler
{
   public IDictionary<string,string> GetData()
   {
       return CacheManager.GetData("ConfigcacheKey") as IDictionary<string,string>;
   }

   public void SetData(string key,string value)
   {
       var data = GetData() ?? new Dictionary<string,string();
       if(data.ContainsKey(key)) data[key] = value;
       else data.Add(key,value);

       CacheManager.Add("ConfigcacheKey", data);

       // HERE write an async method to save the key,value in database or XML file
   }
}

如果您使用 XML,那么您不需要每次都将字典转换为 xml。在 XmlDocument/XDocument 对象中加载 XML 文档,并使用 XPath 查找元素以更新值或添加新元素并保存文档。

从性能的角度来看,除非您执行一些疯狂的逻辑或处理以 GB 为单位的大量(我的意思是非常庞大的)数据,否则我建议您使用已经可用的经过实战测试的组件(如数据库、缓存管理器)快速完成您的应用程序,这些组件将您从线程安全操作中抽象出来.

【讨论】:

    【解决方案2】:

    我看到了解决这个问题的两种可能的方法:

    • 使用数据库。 IMO 这是首选方法,因为这正是数据库的设计目的:多个应用程序的并发读/写访问。
    • 使用“服务”应用程序来管理资源并且可以被其他应用程序访问(管道、套接字、SharedMem 等)。

    要记住的关键点:

    1. GlobalMutex 不能跨多台机器工作(XML 文件可能位于网络共享上。如果不能将其排除为“不受支持”,则不应使用 Mutex)。
    2. “锁定文件”可能会泄漏锁定(例如,如果创建锁定文件的进程被杀死,该文件可能会保留在磁盘上)
    3. 如果文件被多个进程重复更新,XML 是一种非常糟糕的格式(例如,如果每次访问都需要“加载-更新-写入”,这将导致性能非常差)。

    【讨论】:

      【解决方案3】:

      将您的解决方案基于此 Stackoverflow 答案的设计原则:

      How to effectively log asynchronously?

      正如您在考虑之一中提到的,上述解决方案涉及线程和排队。

      此外,您可以使用BinaryFormatter 获得更好的性能,而不是将数据序列化为 XML

      【讨论】:

      • 嗯,我还没有决定写部分。这是我不确定什么是最好的方法。我想到的几个选项是使用 XmlDocument/XDocument/Serialization 来编写。一个新项目也会按照您的建议添加到其中:) 也会检查这个。谢谢。
      • 写一个关于你如何使用这个的答案或接受上述答案以通知我们其他人。
      • 是的,等待其他专家的任何 cmet 或建议。
      【解决方案4】:

      关于性能 - 当大小超过 100MB 时,XML 非常慢。我的要求是在磁盘上读/写数据(~ 1GB),读写操作可能是并行的。例如数据来自 1 个线程,并且正在写入文件中,另一个/相同的应用程序可以要求数据以在图表/其他 UI 上显示。我们转向二进制读写器,我们进行了性能分析,二进制读写器与 XML 相比非常快(对于更大的文件大小)。

      现在我们已经迁移到 HDF5,我们正在播放 20GB 的数据文件,同时进行读写操作。

      具有全局名称的互斥锁 shud 工作,我们使用相同的。

      【讨论】:

      • 你有没有在这种情况下使用过缓存?另外,您是如何处理仅更新部分数据的,还是与读取整个数据并将整个数据从/写入文件有关的事情?你有性能分析的结果吗?如果您可以使用代码 sn-p 更新您的答案,将会有很大帮助吗?
      【解决方案5】:

      我将从单一、轻量级的调控器进程开始,它完全负责访问数据文件。其他进程与调控器通信(即在这种情况下通过IDataHandler 接口通过.NET Remoting)并且从不直接操作文件。这样,您不仅可以抽象出与多路访问相关的问题,还可以获得一些功能:

      • 轻量级、简单的流程更加可靠,并且在任何“消费者”流程失败时不会损坏您的数据
      • 您只有一个代码来维护可靠性、锁定、共享等内容。
      • 每当您决定将 XML 转换为其他内容时 - 只有一个地方可以更改技术

      【讨论】:

      • 你提到的特性已经在我的脑海中,即实现接口的类名(作为单一责任原则的一部分)看起来像 XmlDataHandler。我对设计非常满意,但不确定如何解决与 xml 加载、更新和写入操作以及与之相关的最佳实践有关的性能和可靠性问题。如果您也对这些事情提供一些见解,将会很有帮助.谢谢!!
      • 好吧!许多专家已经建议使用 DB 来抽象我在使用 xml 时正在考虑的问题,但如果我在使用 xml 时得到一些具体的答案,即解决问题的方法,那将有很大的帮助,因为如果没有办法然后我可以去 DB 以其他方式实现使用 xml 文件本身实现一切所需的东西。
      【解决方案6】:

      数据库,毫无疑问。

      如果您不愿创建另一台服务器,只需在网络驱动器上的共享文件上使用 SQLCE(只要您不需要超过 256 个并发连接)。

      没有需要支持的大型数据库,但您可以获得强类型数据以及使用数据库带来的所有其他好处,例如索引、哈希、行版本等。

      如果没有别的,每次您想要查找(或更新、删除、甚至添加,如果您需要唯一键)记录时,它都不必对整个文件进行线性扫描。

      您实际上是在编写一个哈希表,将键映射到值。不要使用元组数组的数据存储等价物。使用真正的永久商店。

      XML 文件的唯一优势(如果它甚至可以很好地使用的话)是人类可读性和可编辑性(如果这甚至是一个奖励...... SSMS 是否很难使用)?

      缺点:

      1) 对所有查询进行线性扫描 2) 应用程序级别没有安全性或密码访问...任何人都可以编辑此 XML 文件。 SQLCE 可以加密和密码锁定。 3) 无类型数据。 4) 详细格式(说真的,JSON 会更好、更快、更小、有类型且人类可读)。 5) SQL > XPath/XSLT 6) 如果您的数据需求增长,您有内置的约束和键。

      我想不出比 SQLCE 实例开销更低且性能更高的解决方案。

      【讨论】:

        【解决方案7】:

        首先要做的事情。您必须忘记将 XML 用于高性能系统。我建议去 JSON。它的轻量级和许多高性能要求的应用程序,如 Foursquare 使用 JSON 来存储他们的数据(虽然不是他们的所有数据)。

        最好尝试一种基于 NOSQL 文档的数据库,而不是使用关系数据库,因为它们专为高性能系统设计,而且很少有人可以保存原始 JSON 格式的数据。我建议选择 MongoDB(具有 C# 驱动程序并支持 LINQ)。还有许多其他基于文档的 NOSQL DB。但我没用过。

        对于并发,您可以使用并发集合之一,特别是ConcurrentDictionary&lt;TKey, TValue&gt;,这样您就不必担心同步问题。

        【讨论】:

        • 感谢您提及 ConcurrentDictionary。
        猜你喜欢
        • 2021-02-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-13
        • 1970-01-01
        相关资源
        最近更新 更多