通过 MPI 发送 java 个对象

Sending java Objects over MPI

我的故事

我开始在 mpiJava and managed to write a working program, but for one or another reason it doesn't want to run on the platform I need it to run on (I don't have any permissions to install anything). I'm not sure whether it was necessary (considering I get the same problems now), but I started using open-mpi 中编写一个 mpi 程序及其 java 绑定。重点是在平台上,open-mpi 可用,因此我认为它会自动运行。它没有用,我仍在尝试找出原因(它可能与信用系统有关),但这不是我希望在这里解决的问题。

我的问题

真正的问题是我需要通过 MPI 发送 java 对象,但我不知道如何以正确的方式进行。在 mpiJava 中我有优势,有一个可用的 MPI.Object 数据类型(它只是序列化了对象),但是 open-mpi 没有类似的东西。我已经访问了一个 post on BigInteger and a post actually providing some answers and of course the open-mpi reference,但我现在不完全确定在我的案例中什么是最好的方法。

我想通过 MPI 发送 3 个不同的对象:

  1. 一个classic BigInteger
  2. a classic Object[] 里面有 3 个不同的对象
  3. 一个less classic自写class包含对另一个自写class
  4. 的引用

自己写的class是这样的:

public class AC implements Iterable<BS>, Comparable<AC>, LE, Serializable {

    private static final long serialVersionUID = -530910801257060853L;
    private static AC emptyAC = new AC();
    private static AC emptySetAC = new AC();
    static {emptySetAC.theAC.set(0);}
    
    private BitSet theAC = new BitSet();
    private BS universe = BS.universe();
    ...
    //methods
}

public class BS implements Iterable<Integer>, Comparable<BS>, Serializable {

    private static final long serialVersionUID = 4240724082500295998L;
    private static BS theEmptySet = new BS();
    private static long[] bits;

    private long theSet;
    ...
    //methods
}

到目前为止,我的列表中用于发送(省略 'trivial' BigInteger)的 open-mpi 代码如下所示:

public static void main(String[] args) {
    
    ...
    
    //master code

    SortedMap<AC, Long> functions = new TreeMap<>();
    AC u = AC.oneSetAC(BS.universe(n));
    SortedMap<AC, BigInteger> leftIntervalSize = new TreeMap<>();
    MPI.COMM_WORLD.bcast(new Object[]{functions, leftIntervalSize, u}, 3, MPI.Object, 0);

    ...

    AC[] sendbuf = new AC[1];
    while(iterator.hasnext()) {
        MPI.COMM_WORLD.send(sendbuf, 1, MPI.OBJECT, i, 0);
    }

    ...

    //worker code
    Object[] buf = new Object[3];
    MPI.COMM_WORLD.bcast(buf, 3, MPI.OBJECT, 0);

    ...
    
    AC[] func = new AC[1];
    Status stat = MPI.COMM_WORLD.recv(func, 1, MPI.OBJECT, 0, MPI.ANY_TAG);
    
    ...
}

请注意,MPI.Object 只是我的 mpiJava 实现的继承,这些是我需要正确更改的行。

建议的解决方案

我已经有了一些想法,我想我可以使用 the post actually providing some answers for the BigInteger if somebody could give me an example of how to use the MPI struct properly. (I really don't understand it completely from the open-mpi reference 的答案。另一方面,对于我自己的 classes 和 Object[],我可以执行以下任一操作:

  1. 只是序列化该死的对象。
  2. 使用 MPI 结构(在我了解如何使用它之后)。
  3. 押注所需的字节数并将它们作为字节发送。 (如果这可行,我会感到惊讶)。
  4. 使用我即将听说的一些其他功能。

我的问题

  1. 任何人都可以给我一个关于如何在 java 中使用 MPI 结构的例子吗? (也许适用于我的示例之一?)
  2. 谁能告诉我在任何情况下更可取的策略(在序列化的情况下,指出陷阱)?

抱歉拖了这么久post,但我宁愿第一时间说清楚

提前致谢

如果你控制通信的双方并且都在Java 你不太关心性能,那么你可以做这样的事情:

MyClass someObject = ...
serialized = ""
try {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(someObject);
    oos.flush();
    serialized = baos.toString();
} 
catch (Exception e) {
    System.out.println(e);    
}
char [] message = serialized.toCharArray() ;
MPI.COMM_WORLD.Send(message, 0, message.length, MPI.CHAR, 1, 99) ;

另一方面,您只是接收并基本上执行相同的反序列化步骤。

try {
    byte b[] = serializedObject.getBytes(); 
    ByteArrayInputStream bis = new ByteArrayInputStream(b);
    ObjectInputStream ois = new ObjectInputStream(bis);
    MyClass obj = (MyClass) ois.readObject();
} catch (Exception e) {
    System.out.println(e);
}

这种方法的优点是 简单 并且可以让您快速进行。如果您不打算发送很多对象,我认为完全可以接受。

最终,我决定使用 sdotdi 的答案序列化 Object[]。因为广播只发生一次,所以应该不会太糟糕。
对于 BigInteger,我使用了 toByteArray() 方法并首先发送数组的长度,然后发送字节数组本身。我怀疑它几乎与使用 MPI 的结构一样快,但我不太确定。因此,代码如下所示:

byte[] bigintbuf = result.toByteArray();
MPI.COMM_WORLD.send(new int[]{bigintbuf.length}, 1, MPI.INT, 0, NUMTAG);
MPI.COMM_WORLD.send(bigintbuf, bigintbuf.length, MPI.BYTE, 0, 0);

对于 AC class,我通过实现 toLongArray() 方法应用了类似的技巧,因此代码变为:

long[] acbuf = next.toLongArray();
MPI.COMM_WORLD.send(new int[]{acbuf.length}, 1, MPI.INT, i, NUMTAG);
MPI.COMM_WORLD.send(acbuf, acbuf.length, MPI.LONG, i, 0);

它可能仍然不是执行此操作的最佳方法,但我想它接近最佳性能相当不错。