2

我被赋予了重写一些用 C# 编写的库的任务,这样一旦启动完成就没有分配。

我刚做了一个项目,该项目每 30 秒通过 OdbcConnection 进行一些数据库查询。我一直只使用创建 OdbcDataReader 的 .ExecuteReader()。是否有任何模式(如 SocketAsyncEventArgs 套接字模式)可以让您重新使用自己的 OdbcDataReader?或者其他一些避免分配的聪明方法?

我没有费心去学习 LINQ,因为工作中的所有数据库都是基于 Oracle 的,而我最后一次检查时,没有官方的 Linq To Oracle 提供程序。但如果在 Linq 中有一种方法可以做到这一点,我可以使用第三方方法之一。

更新:

我认为我没有明确说明 no-alloc 要求的原因。我们有一个关键线程正在运行,它不会冻结非常重要。这是一个近乎实时的交易应用程序,我们确实看到某些 Gen 2 集合的冻结时间长达 100 毫秒。(我也听说过用 C# 以同样的方式编写游戏)。有一个后台线程会进行一些合规性检查,每 30 秒运行一次。它现在进行数据库查询。查询非常慢(返回所有数据大约需要 500 毫秒),但这没关系,因为它不会干扰关键线程。除非工作线程正在分配内存,否则会导致 GC 冻结所有线程。

有人告诉我,所有库(包括这个库)在启动后都无法分配内存。无论我是否同意,这都是签署支票的人的要求:)。

现在,显然有一些方法可以让我在没有分配的情况下将数据放入这个过程。我可以设置另一个进程并使用套接字将其连接到这个进程。使用新的 SocketAsyncEventArgs 模式,新的 .NET 3.5 套接字经过专门优化,根本不分配。(事实上​​,我们使用它们来连接多个系统,并且从未看到来自它们的任何 GC。)然后有一个从套接字读取并遍历数据的预分配字节数组,沿途不分配任何字符串。(我不熟悉 .NET 中其他形式的 IPC,所以我不确定内存映射文件和命名管道是否分配)。

但是,如果有一种更快的方法来完成这个 no-alloc 查询而无需经历所有的麻烦,我会更喜欢它。

4

3 回答 3

3

您不能重用IDataReader(或OdbcDataReaderSqlDataReader任何等效类)。它们被设计为仅用于单个查询。这些对象封装了一个单一的记录集,所以一旦你获得并迭代它,它就没有任何意义了。

无论如何,创建数据读取器是一项非常便宜的操作,与实际执行查询的成本相比,它微不足道。我看不出这种“无分配”要求的合理原因。

我什至可以说几乎不可能重写库以不分配内存。即使像装箱整数或使用字符串变量这样简单的事情也会分配一些内存。即使以某种方式可以重用阅读器(正如我解释的那样,它不是),它仍然必须再次向数据库发出查询,这需要以准备查询的形式分配内存,发送它通过网络,再次检索结果等。

避免内存分配根本不是一个实际的目标。如果并且当您确定某些特定操作占用过多内存时,最好避免特定类型的内存分配。

于 2010-04-10T20:59:36.017 回答
2

对于这样的需求,您确定选择像 C# 这样的高级语言吗?
您不能说您使用的 .NET 库函数是否在内部分配内存。该标准不保证这一点,因此如果他们没有在当前版本的 .NET 框架中使用分配,他们可能会在以后开始这样做。

于 2010-04-10T21:00:26.373 回答
1

我建议您分析应用程序以确定时间和/或内存花费在哪里。不要猜——你只会猜错。

于 2010-04-10T21:01:32.280 回答