Java 在不同语言的进程之间高效地共享数据 上下文

Java 在不同语言的进程之间高效地共享数据 上下文,java,c#,.net,ipc,Java,C#,.net,Ipc,我正在编写一个Java程序,通过标准输入和标准输出与C#程序进行通信。C#程序作为子进程启动。它通过stdin获取“请求”,并通过stdout发送“响应”。请求非常轻量级(只有几个字节大小),但响应很大。在程序的正常运行中,响应量约为2GB的数据 我正在寻找提高性能的方法,我的测量结果表明,向标准输出写入数据是一个瓶颈。以下是正常运行的数据: 总时间:195秒 通过标准输出传输的数据:2026MB 写入标准输出的时间:85秒 标准输出吞吐量:23.8 MB/s 顺便说一下,我首先将所有字节写

我正在编写一个Java程序,通过标准输入和标准输出与C#程序进行通信。C#程序作为子进程启动。它通过stdin获取“请求”,并通过stdout发送“响应”。请求非常轻量级(只有几个字节大小),但响应很大。在程序的正常运行中,响应量约为2GB的数据

我正在寻找提高性能的方法,我的测量结果表明,向标准输出写入数据是一个瓶颈。以下是正常运行的数据:

  • 总时间:195秒
  • 通过标准输出传输的数据:2026MB
  • 写入标准输出的时间:85秒
  • 标准输出吞吐量:23.8 MB/s
顺便说一下,我首先将所有字节写入内存缓冲区,然后一次性将它们复制到标准输出,以确保只测量标准输出写入时间

问题: 在C#子进程和Java父进程之间共享数据的高效而优雅的方式是什么?很明显,stdout是不够的


我到处都读过关于通过内存映射文件共享内存的文章,但是Java和.NET API给我的印象是我找错了地方。

在你投资更多内存映射文件或命名管道之前,我首先要检查你是否真的读写有效
java.lang.Process.getInputStream()
使用BufferedInputStream,因此读卡器端应该是正常的。但是在你的C程序中,你很可能会使用控制台。这里的问题是默认情况下启用了自动刷新。因此,每一次写入都会明确地刷新流。我上一个C#代码是几年前写的,所以我不是最新的。但是,也许可以将Console.Out的AutoFlush属性设置为false,并在多次写入后手动刷新流

如果禁用自动刷新,则不应该是使用Console提高性能的唯一方法

另一个潜在的瓶颈可能是中间的shell,它必须解释写入的数据。确保直接执行C#程序,而不是通过脚本或调用命令执行器


在开始使用内存映射文件之前,我首先尝试简单地写入一个文件。只要您有足够的空闲内存,而这些内存不是您的程序或其他程序使用的,并且只要没有其他经常访问磁盘的程序,操作系统就能够在文件系统缓存中保存大量的写入数据。只要Java程序读取文件的速度足够快,而C#程序正在写入文件,就很可能只需要从磁盘加载一些数据,甚至不需要从磁盘加载数据。

正如Matthew Watson在评论中提到的,使用内存映射文件确实是可能的,而且速度非常快。事实上,我的程序的吞吐量从24MB/s增加到180MB/s。下面是它的要点

以下Java代码创建用于通信的内存映射文件,并打开一个我们可以读取的缓冲区:

var path=path.get(“test.mmap”);
var channel=FileChannel.open(路径,StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
var mappedByteBuffer=channel.map(FileChannel.MapMode.READ_WRITE,0200_000*8);
以下C#代码打开内存映射文件并创建一个可用于向其写入字节的流(请注意,
buffer
是要写入的字节数组的名称):

//此代码假定文件已在Java端创建
var file=file.Open(“test.mmap”,FileMode.Open,FileAccess.ReadWrite,FileShare.ReadWrite);
var memoryMappedFile=memoryMappedFile.CreateFromFile(文件,文件名,0,MemoryMappedFileAccess.ReadWrite,HandleInheritability.None,false);
var stream=memoryMappedFile.CreateViewStream();
stream.Write(buffer,0,buffer.Length);
stream.Flush();

当然,您需要以某种方式同步Java和C端。为了简单起见,我没有将其包含在上面的代码中。在我的代码中,当读/写是安全的时,我使用标准IN和标准输出信号。

可能考虑一个命名管道,或者(可能是最快的,但更费力地编排)一个内存映射文件。Java(显然还有C#)也可以访问这两个库。您只需将响应内容保存为文件或缓存,然后在您的ResponseAnks中包含一个指向此内容的指针即可获得答案!我直接通过字节(抱歉,只是更新了问题以使其更清楚)向stdout写信,这样就可以了。我将尝试使用文件的方法,看看效果如何。