应用之间的对象共享?

bra*_*don 9 c# object sharing interprocess

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

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

Mic*_*kyD 29

虽然早期的WCF今天仍然相关,但您可以使用一些IPC技术.

管道

管道就是这样一种技术.它是二进制的,在内核模式下运行非常快!虽然它的级别很低,但却无法访问"对象".

.NET Remoting

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

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

COM

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

A 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";

}
Run Code Online (Sandbox Code Playgroud)

现在为工厂模式:

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof (IFactory))]
[Guid("...")]
[ProgId(MyComLibConstants.FactoryProgId)]
public class Factory : MarshalByRefObject, IFactory
{
    #region IFactory Members

    /// <summary>
    /// Creates the manager.
    /// </summary>
    /// <returns></returns>
    public IManager CreateManager()
    {
        return Manager.Instance;
    }


    #endregion
}
Run Code Online (Sandbox Code Playgroud)

管理者:

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof (IManager))]
[Guid("...")]
internal sealed class Manager : MarshalByRefObject, IManager
{
    private static Manager _instance;

    #region Constructor

    /// <summary>
    /// Prevents a default instance of the <see cref="Manager"/> class from being created.
    /// </summary>
    private Manager()
    {
        const int n = 5000;
        Array = new IArrayItem[n];
        for (int i = 0; i < n; i++)
        {
            Array[i]=new ArrayItem();
        }
    }

    #endregion

    #region Properties


    /// <summary>
    /// Gets the instance.
    /// </summary>
    /// <value>
    /// The instance.
    /// </value>
    public static IManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new Manager();
            }
            return _instance;
        }
    }

    #endregion

    #region IManager Members

    /// <summary>
    /// Gets the array.
    /// </summary>
    /// <value>
    /// The array.
    /// </value>
    public IArrayItem[] Array { get; private set; }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

一个测试应用程序 这应该引用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

文件映射/共享内存

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

MSDN:

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

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

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

告诉我更多

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

  • [LPC(本地过程调用)第 1 部分架构 – Ntdebugging 博客](https://blogs.msdn.microsoft.com/ntdebugging/2007/07/26/lpc-local-procedure-calls-part-1-architecture/) (2认同)