应用之间的对象共享?

假设我的大数据arrays每秒更新1000次以上。
另一个应用程序想要在短时间内访问和读取数组。 两个应用程序都在同一台机器上。

我已经尝试使用WCF进行进程间通信,但是每秒数千次序列化和发送整个数组(或大型对象)是不可行的性能。
有没有办法直接访问c#中不同应用程序的对象?

您可以使用一些IPC技术,尽管今天的WCF仍然存在。

管道

管道就是这样一种技术。 它是二进制的,在内核模式下运行并且非常快! 虽然它很低级但不能访问“对象”。

.NET Remoting

.NET Remoting将提供对象的访问权限,但可能没有管道那么快。

管道和.NET远程处理都比序列化技术WCF更快,后者将事物转换为详细的XML / SOAP。

COM

COM是IPC的二进制协议。 COM是客户端服务器模型,客户端从COM或OLE服务器请求数据。 关于COM的美妙之处在于您可以直接访问服务器中的对象 – 它们不是序列化的。 例如,请求SAFEARRAY中的元素。

SAFEARRAY是一种由类型安全数据组成的任意维度的自动化安全结构。 幸运的是.NET会为我们隐藏SAFEARRAY狼吞虎咽的东西。

在我的示例中,我创建了一个将公开数组的Manager类。 为了进入Manager我使用了工厂模式,因此Manager基本上是一个单例。

您应按如下方式布置项目:

  • MyComLib.Contracts.dll – 包含所有接口
  • MyComLib.dll – 包含FactoryManager的实现

首先是合同:

 [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IArrayItem { #region Properties string Name { get; set; } int Whatsit { get; set; } #endregion } [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IFactory { #region Methods IManager CreateManager(); #endregion } [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IManager { #region Properties IArrayItem[] Array { get; } #endregion } public static class MyComLibConstants { public const string FactoryProgId = "MickyD.MyComLib.Factory.1"; } 

现在为工厂模式:

 [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] [ComDefaultInterface(typeof (IFactory))] [Guid("...")] [ProgId(MyComLibConstants.FactoryProgId)] public class Factory : MarshalByRefObject, IFactory { #region IFactory Members ///  /// Creates the manager. ///  ///  public IManager CreateManager() { return Manager.Instance; } #endregion } 

管理者:

 [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] [ComDefaultInterface(typeof (IManager))] [Guid("...")] internal sealed class Manager : MarshalByRefObject, IManager { private static Manager _instance; #region Constructor ///  /// Prevents a default instance of the  class from being created. ///  private Manager() { const int n = 5000; Array = new IArrayItem[n]; for (int i = 0; i < n; i++) { Array[i]=new ArrayItem(); } } #endregion #region Properties ///  /// Gets the instance. ///  ///  /// The instance. ///  public static IManager Instance { get { if (_instance == null) { _instance = new Manager(); } return _instance; } } #endregion #region IManager Members ///  /// Gets the array. ///  ///  /// The array. ///  public IArrayItem[] Array { get; private set; } #endregion } 

一个测试应用程序 这应该引用MyComLib.Contracts.dll不是MyComLib.dll

 class Program { static void Main(string[] args) { var type = Type.GetTypeFromProgID(MyComLibConstants.FactoryProgId); var factory = Activator.CreateInstance(type) as IFactory; var manager = factory.CreateManager(); var x = manager.Array[500].Whasit; } } 

最后一步是将此进程内 COM服务器更改为进程外 COM服务器,以便多个进程各自共享同一个Manager ,而不创建自己的单例。 换句话说,跨越进程的单身人士。 当Manager运行时,它基本上位于与所有其他客户端进程分开的自己的进程空间中。

为此,您需要配置COM代理, 此处详细说明。

文件映射/共享内存

最后,文件映射允许您操作文件,就好像它只是进程地址空间中的大块内存一样。 没有繁琐的文件寻求; 读/写操作。 只需抓住指向内存块的指针,然后开始读/写。 系统将完成剩下的工作。

MSDN:

您可以使用特殊的文件映射案例在进程之间提供命名共享内存。 如果在创建文件映射对象时指定系统交换文件,则将文件映射对象视为共享内存块。 其他进程可以通过打开相同的文件映射对象来访问同一块内存。 告诉我更多

遗憾的是,它仍然需要您首先编写数据并且为了最有效,您需要更改应用程序以将内存块视为事实的来源,而不是内存中的数组。 否则你将一直在序列化。

但是,通过交换文件共享内存在技术上允许您消除客户端 – 服务器应用程序与“堆上”数据重复之间的任何序列化反序列化。 虽然正如我所说,您可能需要调整您的应用程序以使用原始内存缓冲区而不是对象。

告诉我更多

  • .NET Framework中的管道操作
  • .NET Remoting
  • 进程间通信

注意:与流行的看法相反,.NET Remoting 并不完全过时 。 一个通用的用途是在同一进程中不同AppDomains中的对象之间的通信,这通常是您在plug-in systems所做的事情。