优化/读取/写入共享资源的最佳方式

时间:2014-08-16 18:39:06

标签: c# multithreading performance optimization file-io

我需要的是管理共享资源(更像是日志,同时具有读写操作)

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

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

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

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

因此我正在考虑使用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决定以及数据是否增长  我会把它移到DB。 此外,与读取操作相比,写入数据会更多。

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

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

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

  • 我正在考虑将数据缓存(。MemoryCache。)这些数据作为字典,这将启用

在读取操作期间实现性能,是否可以在内存中缓存500 MB数据,或者我们

还有其他选择吗?

  • 现在,如果我使用上述缓存机制,在写操作期间应该发生什么:

  • 我应该通过转换

  • 在每次写入操作期间再次将字典内容写入xml

整个字典到xml?要么   - 有没有办法只更新其数据被修改/添加的xml文件的一部分?或任何

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

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

因为写入文件而不会受到影响?   - 要处理多线程场景,计划使用具有全局名称的Mutex,还有其他

更好的方法吗?

我确信,我操作的假设很少,并试图从那里建造,如果我错了

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

欢迎(保持表现为主要标准)。 提前谢谢。

7 个答案:

答案 0 :(得分:3)

正如您所说的“写操作不仅仅是读取”我假设数据增长得更快,因此我的建议是开始设计数据库。它不需要像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中的巨大(我的意思是非常巨大的)数据,我建议你使用已经可用的经过测试的组件(如数据库,CacheManagers)快速完成你的应用程序,它们将你从线程安全操作中抽象出来

答案 1 :(得分:2)

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

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

要记住的关键点:

  1. GlobalMutex无法在多台计算机上运行(XML文件可能位于网络共享上。如果不能将其视为“不支持”,则不应使用互斥锁。)
  2. “锁定文件”可能会泄漏锁定(例如,如果创建锁定文件的进程被终止,则文件可能会保留在磁盘上)
  3. 如果一个文件被多个进程反复更新,则XML格式非常糟糕(例如,如果每次访问需要“load-update-write”,那么性能将非常差)。

答案 2 :(得分:1)

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

How to effectively log asynchronously?

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

此外,使用BinaryFormatter

可以获得更好的性能,而不是将数据序列化为XML。

答案 3 :(得分:1)

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

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

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

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

数据库,毫无疑问。

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

没有大型数据库可供支持,但您可以获得强类型数据以及使用数据库所产生的所有其他好处,例如索引,哈希,反转等等。

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

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

你对XML文件的唯一优势(如果甚至可以使用得好)是人类的可读性和可编辑性(如果这甚至是奖励......难以使用的SSMS)?

缺点:

1)所有查询的线性扫描 2)在应用程序级别没有安全性或密码访问权限......任何人都可以编辑此XML文件。 SQLCE可以加密并密码锁定。 3)无类型数据。 4)详细格式(严肃地说,JSON会更好,更快,更小,类型和人类可读)。 5)SQL&gt;的XPath / XSLT 6)如果您的数据需求增长,则您具有内置约束和密钥。

我无法想象一个性能更高的解决方案,其开销比SQLCE实例更少。

答案 6 :(得分:1)

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

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

对于并发性,您可以使用其中一个并发集合,尤其是ConcurrentDictionary<TKey, TValue>,这样您就不必担心同步问题了。