C# 应用程序之间的对象共享?

C# 应用程序之间的对象共享?,c#,object,sharing,interprocess,C#,Object,Sharing,Interprocess,假设我有一个每秒更新1000多次的大型数据阵列。 另一个应用程序希望在短时间内访问和读取阵列。两个应用程序都在同一台机器上 我曾尝试使用WCF进行进程间通信,但在性能方面,每秒串行化和发送整个阵列(或大型对象)数千次是不可行的。 在c#中是否有一种方法可以直接访问来自不同应用程序的对象?有一些IPC技术可以使用,尽管最新的WCF在今天仍然适用 管 管道就是这样一种技术。它是二进制的,在内核模式下运行,速度非常快!虽然它的级别很低,并且不允许访问“对象” .NET远程处理 .NET远程处理将提供对

假设我有一个每秒更新1000多次的大型数据阵列。
另一个应用程序希望在短时间内访问和读取阵列。两个应用程序都在同一台机器上

我曾尝试使用WCF进行进程间通信,但在性能方面,每秒串行化和发送整个阵列(或大型对象)数千次是不可行的。

在c#中是否有一种方法可以直接访问来自不同应用程序的对象?

有一些IPC技术可以使用,尽管最新的WCF在今天仍然适用

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

.NET远程处理 .NET远程处理将提供对对象的访问,但速度可能不如管道

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

组件对象模型 COM是IPC的二进制协议。COM是一种客户机-服务器模型,其中客户机从COM或OLE服务器请求数据。COM的优点在于,您可以直接访问服务器中的对象,而不是序列化对象。例如,请求中的元素

SAFEARRAY
是由类型安全数据组成的任意维度的自动化安全结构。幸运的是.NET将为我们隐藏安全阵列的gobble de gook

在我的示例中,我创建了一个
管理器
类来公开数组。为了访问
管理器
,我使用了工厂模式,因此
管理器
本质上是一个单例

您应该按照以下方式规划您的项目:

  • mycmlib.Contracts.dll-包含所有接口
  • mycmlib.dll-包含
    工厂
    管理器
首先,合同:

[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

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


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

为此,您需要配置一个COM代理,详细说明了这一点

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

MSDN:

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

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

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

告诉我更多

注意:与流行的观点相反,.NET远程并非完全过时。它的一个上下文用途是同一进程中不同
应用域中的对象之间的通信,这是在
插件系统中通常要做的事情

您在做什么,每秒更新数据数组1000多次?这听起来像是一个原型问题。您真的需要实时发送每个更新吗?你能把更新排队吗?您能否批量更新,以便在“消息”中发送多个更新?perhaps@Scott张伯伦游戏/模拟,它们需要实时处理。是的,也许将组件分离并在不同的应用程序中运行是一种有缺陷的方法。如果是游戏,我会重新评估您从不同的应用程序中获得的净收益,以及这些收益是否值得这种缓慢的成本。如果是模拟,我会尝试批处理或排队发送数据,将数据分成较大的数据块,以便分摊每次更新的开销。@pm100 sharedmemory听起来不错,但它只能共享缓冲区和原语数组,不能共享对象,不能共享对象数组-它们必须序列化,然后写入共享缓冲区,与pipes相同。WCF已使用命名管道,但所有内容都将序列化。我所读到的NetRemoting也序列化了通信数据。我确实提到了这一点。序列化并不总是相同的-WCF使用反射,可以作为详细的XML/SOAP持久化。在我的建议中,我是说您
完全绕过WCF
并发送原始二进制数据-您在字节级别控制序列化。这将大大超过WCF。祝你好运@brandon WCF是某种连接(可以称为管道、TCP或其他)上的包装器,以使其更易于使用。那个包装器需要花费一定的开销。Micky的建议是剥离包装器,转而使用原始构造,并进行您自己的定制专门化,可以尽可能快地进行调整。@user2481095我希望共享内存是最快的,因为不涉及方法调用/vtable。只要不涉及网络层,Protobuf就可能有用。当然会的
[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
}
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;
    }
}