【发布时间】:2017-02-14 04:49:12
【问题描述】:
设计: 我的 C# WCF 进程必须在内存中缓存大量数据(作为字典) - 进程占用的内存增长超过 1.5GB。缓存中的数据或多或少来自数据库(使用实体框架)。缓存的构建方式是: 在表上选择查询以从表中获取主键列表(例如字符串列表)。假设我得到一个包含 1000 个项目的列表。 现在我在这个主键列表上执行 Parallel.Foreach 并且(foreach 的主体)操作是转到数据库并获取该键的所有数据(即从 KeyColumn = 循环项的表中选择 *)。对数据进行一些操作,然后将其添加到缓存(字典)中。
问题: 当进程/可执行文件启动时。它消耗了几乎 95% 的 CPU(这很好)并且占用了 RAM(比如 1.3 或 1.4 GB)。运行良好,直到前 10-12 分钟。但是后来不知什么原因,CPU 下降到 15-17% RAM,稳定在 1.4GB(还有更多)。而且我可以看到数据库中的几个项目尚未添加到缓存中。这种 Frozen 状态会持续很长时间(有时 10 小时),然后一切都会处理,所有数据都在我的缓存中。 RAM 现在稳定在 1.5GB 左右。我认为 GC 周期会冻结应用程序线程,但随后(因为它是 WCF 服务)任何服务方法调用都会响应。它只是那个似乎每次都冻结的并行线程部分,每次重新启动时都以相同的 RAM 大小......而且数据方面每次都从缓存中丢失相同的一组项目。 我已经验证了那些众所周知的缺失键的数据没有什么不同。
寻找任何关于似乎有问题的指针?
编辑
简单来说,我的代码流程如下:
ConcurrentDictionary<string, string> MyCache = new ConcurrentDictionary<string, string>();
private List<string> GetPrimaryKeysFromDB()
{
using(var ctx = new MyDBContext())
{
List<string> results = ctx.MyTable.Select(x=>x.PrimeColumn).ToList();
return results;
}
}
private void SomeMethod()
{
List<string> ListOfPrimeItems = GetPrimaryKeysFromDB();
Parallel.Foreach(ListOfPrimeItems, #MaxDopSetting#, k =>
{
ProcessDataForKey(k);
});
}
private void ProcessDataForKey(string key)
{
// Goto DB and fetch record for key
// Each column (Entity data member) will undergo some processing here
// some string manipulations
// Finally convert the new state of data to XML (serialize) and store in cache
MyCache[key] = TranslatedStateOfData;
}
【问题讨论】:
-
错的是不要那样做。如果您的数据库太慢,请让它更快,那么缓存层就是 1990 年代。除此之外,请查看 ParallelOptions.MaxDegreeofParallelism,将其设置为您拥有的核心数量或最多翻倍。
-
感谢您的回复本。但是,我需要转换数据的高/快速可用性(因此是缓存)。默认MaxDOP设置不是最推荐的一种来源:link
-
您需要更多信息来调试此类问题。您的代码中的任何行(与 .NET 框架相反)是否在“爬行”时执行?你有一些Minimal, Complete, and Verifiable code 供我们试用吗?通常这种爬取是两件事的结果:Thrashing 或等待/同步
-
你的机器有多少内存?它是64位进程吗?一旦超过物理 RAM,您将开始分页,一切都会变慢。一旦超过一定比例的物理 RAM,就会开始进行垃圾收集以恢复内存。在我看来,您只是没有足够的 RAM 和/或地址空间。
-
这是在一个相当不错的服务器(64 位)多 CPU(我猜是 Xeon 的)上,测试机器上有大约 16 个核心(超过 32GB RAM)。将 MaxDOP 设置为 Environment.ProcessorCount 并使用 ConcurrentDictionary 而不是 Dictionary 没有帮助。情况是一样的。由于我的工作性质,无法分享大部分代码。
标签: c# .net multithreading task-parallel-library