【问题标题】:Sending java Objects over MPI通过 MPI 发送 java 对象
【发布时间】:2015-05-06 12:08:42
【问题描述】:

我的故事

我开始在mpiJava 中编写一个 mpi 程序并设法编写了一个工作程序,但由于某种原因它不想在我需要它运行的平台上运行(我没有任何安装任何东西的权限)。我不确定是否有必要(考虑到我现在遇到同样的问题),但我开始使用 open-mpi 及其 java-bindings。关键是在平台上,open-mpi 是可用的,因此我认为它会自动工作。它没有用,我仍在试图找出原因(它可能与信用系统有关),但这不是我希望在这里解决的问题。

我的问题

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

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

  1. 经典之作BigInteger
  2. 经典的 Object[] 里面有 3 个不同的对象
  3. 一个不太经典的自写类,包含对另一个自写类的引用

自写的类是这样的:

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
}

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

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 实现的继承,这些是我需要正确更改的行。

建议的解决方案

我已经对此有了一些想法,我假设如果有人可以给我一个如何正确使用 MPI 结构的示例,我可以使用来自the post actually providing some answers 的答案作为BigInteger。 (我真的不完全从the open-mpi reference 中理解它。另一方面,对于我自己的课程和Object[],我可以执行以下任一操作:

  1. 只需序列化血腥对象即可。
  2. 使用 MPI 结构(在我知道如何使用它之后)。
  3. 赌上所需的字节数并将它们作为字节发送。 (如果这行得通,我会感到惊讶)。
  4. 使用我即将听到的其他一些功能。

我的问题

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

很抱歉这篇文章太长了,但我希望从一开始就清楚。

提前致谢

【问题讨论】:

    标签: java performance data-structures mpi


    【解决方案1】:

    如果您控制通信的双方并且都使用 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);
    }
    

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

    【讨论】:

    • 我确实关心性能,但我真的不知道如何在 MPI 中使用这个结构构造。我正在考虑序列化Object[],但我认为对于 AC 和 BigInteger,使用结构(或者在任何情况下都会有更有效的方法)会更好。无论如何,感谢您清除序列化。
    • 可以kryo 帮助我更快地获得相同的结果吗?
    • 因为 kryo 的序列化速度更快:是的,它会的。不过,我不能说多少。 FST (ruedigermoeller.github.io/fast-serialization) 应该更快,并且是替代品,而不是 kryo。
    【解决方案2】:

    最后,我决定使用 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 类,我通过实现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);
    

    这可能仍然不是最理想的方法,但我猜它接近最佳性能相当不错。

    【讨论】:

    • 我已经到了序列化对象数组需要整个程序运行时间的一半以上的地步,所以如果有人知道改进,仍然欢迎......
    猜你喜欢
    • 2015-12-19
    • 2016-05-07
    • 2014-08-01
    • 2014-01-11
    • 2021-01-11
    • 2015-01-06
    • 1970-01-01
    • 2014-12-10
    • 1970-01-01
    相关资源
    最近更新 更多