目前,我正在开展一个项目,我需要将 GB 的数据带到客户端机器上以执行某些任务,并且该任务需要整个数据,因为它对数据进行一些分析并有助于决策过程。
所以问题是,在不影响客户端机器和应用程序性能的情况下,将大量数据管理到内存中的最佳实践和合适方法是什么。
注意:在应用程序加载时,我们可以花时间将数据从数据库带到客户端机器,这在我们的案例中是完全可以接受的。但是一旦数据在启动时加载到应用程序中,性能就非常重要。
目前,我正在开展一个项目,我需要将 GB 的数据带到客户端机器上以执行某些任务,并且该任务需要整个数据,因为它对数据进行一些分析并有助于决策过程。
所以问题是,在不影响客户端机器和应用程序性能的情况下,将大量数据管理到内存中的最佳实践和合适方法是什么。
注意:在应用程序加载时,我们可以花时间将数据从数据库带到客户端机器,这在我们的案例中是完全可以接受的。但是一旦数据在启动时加载到应用程序中,性能就非常重要。
如果没有问题陈述,即您当前面临什么问题,这有点难以回答,但以下只是一些想法,基于我们最近在类似情况下的一些经验。然而,要改变这种类型的模型需要做很多工作——所以这也取决于你可以投入多少来尝试“修复”它,我不能保证“你的问题”与“我们的问题”是一样的问题”,如果你明白我的意思。因此,如果以下方法对您不起作用,请不要生气!
将这么多数据加载到内存中总是会产生一些影响,但是,我想我明白你在做什么......
当天真地加载这么多数据时,您将拥有许多(数百万?)对象和类似或更多数量的引用。你显然会想要使用 x64,所以引用会加起来——但就性能而言,最大的问题将是垃圾收集。您有很多无法收集的对象,但是 GC 会知道您正在使用大量内存,并且无论如何都会定期尝试。这是我在这里更详细地查看的内容,但下图显示了影响 - 特别是,那些“尖峰”都是 GC 杀死性能:
对于这种情况(大量数据加载,从未释放),我们切换到使用 structs,即将数据加载到:
struct Foo {
private readonly int id;
private readonly double value;
public Foo(int id, double value) {
this.id = id;
this.value = value;
}
public int Id {get{return id;}}
public double Value {get{return value;}}
}
并将它们直接存储在数组(不是列表)中:
Foo[] foos = ...
这样做的意义在于,因为其中一些结构非常大,我们不希望它们在堆栈上多次复制自己,但是使用数组你可以这样做:
private void SomeMethod(ref Foo foo) {
if(foo.Value == ...) {blah blah blah}
}
// call ^^^
int index = 17;
SomeMethod(ref foos[index]);
请注意,我们直接传递了对象——它从未被复制;foo.Value
实际上是直接查看数组内部。当您需要对象之间的关系时,棘手的部分就开始了。您不能在此处存储引用,因为它是 a struct
,并且您不能存储它。但是,您可以做的是存储索引(到数组中)。例如:
struct Customer {
... more not shown
public int FooIndex { get { return fooIndex; } }
}
不如 方便customer.Foo
,但以下效果很好:
Foo foo = foos[customer.FooIndex];
// or, when passing to a method, SomeMethod(ref foos[customer.FooIndex]);
关键点:
int
是 4 个字节;x64 上的引用是 8 个字节)补充说明:
string.Intern
,那会很糟糕)以确保每个重复值只有一个实例,而不是 800,000 个具有相同内容的字符串fixed
数组;这需要unsafe
代码,但避免了另外无数的对象和引用作为一个额外的脚注,对于这么多的数据,您应该非常认真地考虑您的序列化协议,即您如何通过网络发送数据。我强烈建议远离XmlSerializer
,DataContractSerializer
或BinaryFormatter
. 如果您需要有关此主题的指示,请告诉我。