应用之间的对象共享?
假设我的大数据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 – 包含
Factory
,Manager
的实现
首先是合同:
[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
所做的事情。