.NET 能否在进程之间共享大型内存集合?

3
我有一个控制台应用程序,每天运行数百次,并从大型文件(例如50个文件,总大小为3-4 Gb)中读取相同的数据。
我考虑创建一个Windows服务,将数据缓存在内存中以加快访问速度,并控制数据的生命周期(因为这50个文件集可能会随着时间而变化)。
我打算实现共享内存映射文件,因此控制台应用程序将从服务写入的内存中读取文件...
但是还有另一个考虑因素。每次读取的数据都会转换为.NET对象。
所以我的问题是 - 是否有一种方法可以在内存中共享.NET对象(List),而不是文件?
P.S. 数据是手动序列化的一系列字节。

请参考TomTom的答案。作为一种解决方法,如果符合您的要求,您可以创建一个管理数据并在该数据上执行逻辑的服务。如果只是搜索或聚合…… 您的控制台应用程序将简单地调用服务中的方法并处理该方法的结果。 - Polity
3-4 GB 的内存?真的吗?哎呀,这太疼了。。 - Steve
@Polity - 如果可以的话,我就不会使用映射文件等。逻辑本身每天都会变化100次,而数据是静态的。这就是为什么我按照我所解释的方式来做事的原因... - Boppity Bop
对于我们中的一些人来说,3-4 GB 微不足道。我有使用双位数内存缓冲区(10、15GB)的 .net 应用程序。当您跟踪金融工具价格(例如,200,000)并获得一些更新时(例如每秒25,000),将事物保留在内存中是唯一的解决方案。您可以将其写入磁盘,但仍需将当前状态保留在内存中。 - TomTom
不陷入编写完整答案的兔子洞,这是我如何做到的。对于.NET,跨进程共享集合而不需要复制/序列化需要从一开始就进行仔细的整体设计。服务将把内存中的数据存储为一个可连续行的可位移值类型图像(在客户端和服务之间共享的结构体)在服务端共享内存中。然后可以通过侧带控制通道(它本身可以是共享内存的一部分,因此每次启动只需要通信一个IntPtrin-situ共享单个行。 - Glenn Slayden
显示剩余3条评论
4个回答

4
我会将此实现为一个提供套接字服务器的服务,并使控制台 exe 连接到该服务并通过 TCP/IP 发出请求,获取响应。这很容易设置,因为您已经(根据问题)解决了序列化问题,并且非常可扩展。服务可以在内存中保持所有内容运行良好。甚至可以使客户端和服务器成为同一 exe - 只需在启动时检查 Environment.UserInteractive 以决定是客户端还是服务器。

请注意:保持带宽低,并避免聊天式 API;也就是说:不要让客户端思考很多次然后发出 200 个请求;只需将其整个请求打包并发送到服务器即可。让服务器在本地处理这些内容,避免大量的网络流量。


Marc,你应该更好地阅读问题。我已经有解决方案了——映射内存文件。我想知道是否有一种方法可以映射对象而不是文件……你的套接字想法并没有真正帮助——我仍然需要从字节反序列化数百万个对象……另外,你知道命名管道比TCP更快吗?那么你的观点是什么? - Boppity Bop
3
@Bobb,是的,你有一种解决方案,不止一种。你曾询问过“托管”对象,答案是:你不能这样做(你必须像现在做的那样);然而,我的回答重点是“用另一种方式来做。如果你的问题不适合当前情况,那就好了——但我对你的设置不太熟悉,请不要冷嘲热讽。关于命名管道;好的;在我看来,大多数类似的情况下,我们也会为此专门分配中央节点,因此通过网络,即套接字。如果都在本地,那就太好了! - Marc Gravell

3

有没有一种方式可以共享内存中的.NET对象(List)而非文件?

说实在的,不行,分配的对象在特定进程上。

你可以使用类似远程过程调用(remoting)之类的东西,但这基本上就是在进程之间进行访问控制。

你可以共享非托管空间(共享内存),但其中不能包含.NET对象——需要将其编组。


啊 - 是和不是。文件是,但其中的对象不是。海报已经谈到了内存映射文件,问题在于对于每次读取,您必须将其反向编组为结构或对象。它们不提供一种共享类实例的方法,也没有垃圾回收等 - 这是关于分片对象的。共享数据空间 - 是的。不同的问题。 - TomTom

1
  • 如果您每天运行此应用程序一百次,并且正在寻找一种将“数据”保留在内存中的方法,为什么不让应用程序保持运行状态,而不是关闭它并重新启动它呢?

  • 您可以创建一个Windows服务,将文件加载到内存中并对其进行处理。当然,如果停止或重启服务,它将需要重新加载数据。

  • 另一种解决方案是,不要将对象保留在内存中(这只能使用.Remoting或类似的东西完成),而是将文件导入到数据库中,这将加快处理速度,并且可以在进程之间轻松共享。


0
据我所知,你不能直接在多个.NET进程之间共享集合,而必须跨进程边界传输数据。这会产生相当大的CPU开销,并且会消耗缓存进程和客户端中对象的内存。
使用内存映射文件可能可以实现更好的效果,但仍无法直接将.NET对象映射到共享内存上 - 但你说“数据是手动序列化的一系列字节”,因此可能足够接近?
我不太理解.NET memory mapped files,从本地代码来看,最棒的事情就是你只需将文件视为内存指针,而对于.NET MMF,你需要调用访问器方法,因此需要将数据复制到.NET对象中(?)...但它可能比反复读取文件要快得多。

我要做的正是这个。阅读问题:“我将实现共享内存映射文件”... - Boppity Bop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接