並列分散ソフトウェア 電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/sie/
http://www.is.tsukuba.ac.jp/~yas/index-j.html
http://www.hlla.is.tsukuba.ac.jp/~yas/index-j.html
半数近くは、うまく線形な台数効果を観測するのに成功していた。
sakura の CPU 数は、6 なので、6 スレッドか最も速いはずである。それ以上、 スレッドを増やして測定しても、あまり意味はない。逆に、6 以上に増やして よい効果が現れた時には、測定方法が怪しい。
データ量が少なくて、うまく台数効果が図れていない人が何人かいた。
thr_setconcurrency()で要求した数と実際にシステムが割当てる数が食い違う ことがある。スレッドの数も同時に変える。thr_getconcurrency() で確認す る。
きちんと検算している人がいる。
浮動小数点の場合、シングルスレッドで動かした時の答えとマルチスレッドで 動かした時の答えが違うことがある。計算の順序が変るので。
(A+B)+C!=A+(B+C)。
変数や関数の名前も、きちんと考える習慣を付けるとよい。
Jini/RMI 技術を使ってる。
別の Java 仮想計算機間オブジェクトのメソッドを呼び出す仕組み。 RMI いくつかの層を見えなくする。
http://horb.a02.aist.go.jp/horb-j/
インタフェース Remote を付ける。
src/java/rmi/Remote.java public interface Remote {}これを見つけると、コンパイラが特殊なコードを生成する。
java.lang.Object (class) | +--java.rmi.server.RemoteObject (class) | +--java.rmi.server.RemoteServer (class) | +--java.rmi.server.UnicastRemoteObject (class)これに加えて、interface Remote を implements する。
クライアント側は、これに比べて簡単。違いは、サーバに接続する部分部分と、 分散固有の例外を受ける部分。
---------------------------------------------------------------------- 1: // 2: // Counter.java 3: // 4: 5: public interface Counter 6: { 7: void up(); 8: int getValue(); 9: void reset(int newVal); 10: }; ----------------------------------------------------------------------インタフェースを定義しなくてもよいが、リモートとの比較のためにあえて定 義する。
---------------------------------------------------------------------- 1: // 2: // CounterObject.java 3: // 4: public class CounterObject implements Counter 5: { 6: int val; 7: public CounterObject(int initVal) 8: { 9: val = initVal ; 10: } 11: public void up() 12: { 13: val ++ ; 14: } 15: public int getValue() 16: { 17: return( val ); 18: } 19: public void reset(int newVal) 20: { 21: val = newVal ; 22: } 23: }; ----------------------------------------------------------------------
---------------------------------------------------------------------- 1: // 2: // CounterUser.java 3: // 4: 5: class CounterUser 6: { 7: public static void main(String argv[]) 8: { 9: Counter c1 = new CounterObject( 10 ); 10: for( int i=0 ; i<3 ; i++ ) 11: { 12: c1.up(); 13: System.out.println("c1.value=="+c1.getValue()); 14: } 15: } 16: }; ----------------------------------------------------------------------実行例:
---------------------------------------------------------------------- % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/Counter.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/CounterObject.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/CounterUser.java % ls Counter*java Counter.java CounterObject.java CounterUser.java % rm *.class % javac CounterUser.java % ls *.class Counter.class CounterObject.class CounterUser.class % java CounterUser c1.value==11 c1.value==12 c1.value==13 % java CounterUser c1.value==11 c1.value==12 c1.value==13 % ----------------------------------------------------------------------
オブジェクト c1 を、main で作って実行している。実行する度に新しいオブ ジェクトが new される。
---------------------------------------------------------------------- 1: // 2: // RemoteCounter.java 3: // 4: 5: public interface RemoteCounter extends java.rmi.Remote 6: { 7: public void up() throws java.rmi.RemoteException; 8: public int getValue() throws java.rmi.RemoteException; 9: public void reset(int newVal) throws java.rmi.RemoteException; 10: } ----------------------------------------------------------------------リモート・インタフェースの特徴:
---------------------------------------------------------------------- 1: // 2: // RemoteCounterObject.java 3: // 4: 5: import java.rmi.*; 6: import java.rmi.server.*; 7: 8: public class RemoteCounterObject extends java.rmi.server.UnicastRemoteObject 9: implements RemoteCounter 10: { 11: int val; 12: public RemoteCounterObject(int initVal) throws RemoteException 13: { 14: super(); 15: val = initVal ; 16: } 17: public void up() throws java.rmi.RemoteException 18: { 19: val ++ ; 20: } 21: public int getValue() throws java.rmi.RemoteException 22: { 23: return( val ); 24: } 25: public void reset(int newVal) throws java.rmi.RemoteException 26: { 27: val = newVal ; 28: } 29: }; 30: ----------------------------------------------------------------------
オブジェクトは、serialize (直列化) されてコピーで渡される。
---------------------------------------------------------------------- 1: // 2: // RemoteCounterServer.java 3: // 4: 5: import java.rmi.*; 6: import java.rmi.server.*; 7: 8: public class RemoteCounterServer 9: { 10: public static void main(String argv[]) 11: { 12: if( argv.length != 1 ) 13: { 14: System.err.println("Usage% java RemoteCounterServer rmiregistry-portno"); 15: System.exit( 1 ); 16: } 17: String rmiregport = argv[0]; 18: 19: if( System.getSecurityManager() == null ) 20: System.setSecurityManager( new RMISecurityManager() ); 21: 22: try 23: { 24: RemoteCounter c1 = new RemoteCounterObject( 10 ); 25: String c1_name = "rmi://localhost:"+rmiregport+"/Counter/c1" ; 26: Naming.rebind( c1_name,c1 ); 27: 28: RemoteCounter c2 = new RemoteCounterObject( 20 ); 29: String c2_name = "rmi://localhost:"+rmiregport+"/Counter/c2" ; 30: Naming.rebind( c2_name,c2 ); 31: } 32: catch (Exception e) 33: { 34: System.err.println("RemoteCounterServer error:"+e.getMessage()); 35: e.printStackTrace(); 36: } 37: } 38: }; ----------------------------------------------------------------------Exception を catch したら、最後に System.exit( 1 ) した方がよい。
rmiregistry に登録する時には、次のような URL が使える。
port は、rmiregistry が使うポート番号で、デフォルトでは 1099。 大勢で1つのホストを使うとぶつかる。sakura を使う時には、1099 は避ける こと。
string は単なる文字列。フラットな名前空間。
---------------------------------------------------------------------- 1: // 2: // RemoteCounterClient.java 3: // 4: 5: import java.rmi.*; 6: 7: class RemoteCounterClient 8: { 9: public static void main(String argv[]) 10: { 11: if( argv.length != 2 ) 12: { 13: System.err.println("Usage% java RemoteCounterClient hostname rmiregistry-portno"); 14: System.exit( 1 ); 15: } 16: String hostname = argv[0]; 17: String rmiregport = argv[1]; 18: 19: RemoteCounter c1 ; 20: try 21: { 22: if( System.getSecurityManager() == null ) 23: System.setSecurityManager( new RMISecurityManager() ); 24: String c1_name = "rmi://"+hostname+":"+rmiregport+"/Counter/c1"; 25: c1 = (RemoteCounter) Naming.lookup( c1_name ); 26: for( int i=0 ; i<3 ; i++ ) 27: { 28: c1.up(); 29: System.out.println("c1.value=="+c1.getValue()); 30: } 31: } 32: catch (Exception e) 33: { 34: e.printStackTrace(); 35: } 36: } 37: }; ----------------------------------------------------------------------
一方のウインドウで rmiregistry を起動する。ポート番号は、ぶつからない ように uid を使う。rmiregistry は自動的に終了しないので、実験が終わっ たら ^C (Control-C)で殺す。
一方のウインドウでサーバを動作させる。サーバもは自動的に終了しないので、 実験が終わったら ^C (Control-C)で殺す。---------------------------------------------------------------------- % id uid=4031(yshinjo) gid=4031(yshinjo) % rmiregistry 4031 (最後に ^C で止める) ----------------------------------------------------------------------
rmic で作られるRemoteCounterObject*.class のうち、サーバ側側で必要なの は、RemoteCounterObject.class (本体)とRemoteCounterObject_Skel.class (スケルトン、サーバ側スタブ)のみ。RemoteCounterObject_Stub.class は、 不要。---------------------------------------------------------------------- % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounter.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterObject.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterServer.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterServer.policy % rm *class % rmic RemoteCounterObject % ls *class RemoteCounter.class RemoteCounterObject_Skel.class RemoteCounterObject.class RemoteCounterObject_Stub.class % javac RemoteCounterServer.java % java -Djava.security.policy=./RemoteCounterServer.policy RemoteCounterServer 4031 (最後に ^C で止める) ----------------------------------------------------------------------
---------------------------------------------------------------------- % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounter.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterObject.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterClient.java % wget http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-02-07/ex/RemoteCounterClient.policy % rm *class % rmic RemoteCounterObject % ls *class RemoteCounter.class RemoteCounterObject_Skel.class RemoteCounterObject.class RemoteCounterObject_Stub.class % javac RemoteCounterClient.java % java -Djava.security.policy=./RemoteCounterClient.policy RemoteCounterClient localhost 4031 c1.value==11 c1.value==12 c1.value==13 % java -Djava.security.policy=./RemoteCounterClient.policy RemoteCounterClient localhost 4031 c1.value==14 c1.value==15 c1.value==16 % java -Djava.security.policy=./RemoteCounterClient.policy RemoteCounterClient localhost 4031 c1.value==17 c1.value==18 c1.value==19 % ----------------------------------------------------------------------
rmic で作られるRemoteCounterObject*.class のうち、クライアント側で必要 なのは、RemoteCounterObject_Stub.class (クライアント側スタブ)のみ。 RemoteCounterObject.class と RemoteCounterObject_Skel.class は不要。
---------------------------------------------------------------------- 1: // Stub class generated by rmic, do not edit. 2: // Contents subject to change without notice. 3: 4: public final class RemoteCounterObject_Stub 5: extends java.rmi.server.RemoteStub 6: implements RemoteCounter, java.rmi.Remote 7: { 8: private static final java.rmi.server.Operation[] operations = { 9: new java.rmi.server.Operation("int getValue()"), 10: new java.rmi.server.Operation("void reset(int)"), 11: new java.rmi.server.Operation("void up()") 12: }; 13: 14: private static final long interfaceHash = 5217325697641540004L; 15: 16: private static final long serialVersionUID = 2; 17: 18: private static boolean useNewInvoke; 19: private static java.lang.reflect.Method $method_getValue_0; 20: private static java.lang.reflect.Method $method_reset_1; 21: private static java.lang.reflect.Method $method_up_2; 22: 23: static { 24: try { 25: java.rmi.server.RemoteRef.class.getMethod("invoke", 26: new java.lang.Class[] { 27: java.rmi.Remote.class, 28: java.lang.reflect.Method.class, 29: java.lang.Object[].class, 30: long.class 31: }); 32: useNewInvoke = true; 33: $method_getValue_0 = RemoteCounter.class.getMethod("getValue", new java.lang.Class[] {}); 34: $method_reset_1 = RemoteCounter.class.getMethod("reset", new java.lang.Class[] {int.class}); 35: $method_up_2 = RemoteCounter.class.getMethod("up", new java.lang.Class[] {}); 36: } catch (java.lang.NoSuchMethodException e) { 37: useNewInvoke = false; 38: } 39: } 40: 41: // constructors 42: public RemoteCounterObject_Stub() { 43: super(); 44: } 45: public RemoteCounterObject_Stub(java.rmi.server.RemoteRef ref) { 46: super(ref); 47: } 48: 49: // methods from remote interfaces 50: 51: // implementation of getValue() 52: public int getValue() 53: throws java.rmi.RemoteException 54: { 55: try { 56: if (useNewInvoke) { 57: Object $result = ref.invoke(this, $method_getValue_0, null, -1068577784738248554L); 58: return ((java.lang.Integer) $result).intValue(); 59: } else { 60: java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash); 61: ref.invoke(call); 62: int $result; 63: try { 64: java.io.ObjectInput in = call.getInputStream(); 65: $result = in.readInt(); 66: } catch (java.io.IOException e) { 67: throw new java.rmi.UnmarshalException("error unmarshalling return", e); 68: } finally { 69: ref.done(call); 70: } 71: return $result; 72: } 73: } catch (java.lang.RuntimeException e) { 74: throw e; 75: } catch (java.rmi.RemoteException e) { 76: throw e; 77: } catch (java.lang.Exception e) { 78: throw new java.rmi.UnexpectedException("undeclared checked exception", e); 79: } 80: } 81: 82: // implementation of reset(int) 83: public void reset(int $param_int_1) 84: throws java.rmi.RemoteException 85: { 86: try { 87: if (useNewInvoke) { 88: ref.invoke(this, $method_reset_1, new java.lang.Object[] {new java.lang.Integer($param_int_1)}, 2435635625292702899L); 89: } else { 90: java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash); 91: try { 92: java.io.ObjectOutput out = call.getOutputStream(); 93: out.writeInt($param_int_1); 94: } catch (java.io.IOException e) { 95: throw new java.rmi.MarshalException("error marshalling arguments", e); 96: } 97: ref.invoke(call); 98: ref.done(call); 99: } 100: } catch (java.lang.RuntimeException e) { 101: throw e; 102: } catch (java.rmi.RemoteException e) { 103: throw e; 104: } catch (java.lang.Exception e) { 105: throw new java.rmi.UnexpectedException("undeclared checked exception", e); 106: } 107: } 108: 109: // implementation of up() 110: public void up() 111: throws java.rmi.RemoteException 112: { 113: try { 114: if (useNewInvoke) { 115: ref.invoke(this, $method_up_2, null, 4665897731548305845L); 116: } else { 117: java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 2, interfaceHash); 118: ref.invoke(call); 119: ref.done(call); 120: } 121: } catch (java.lang.RuntimeException e) { 122: throw e; 123: } catch (java.rmi.RemoteException e) { 124: throw e; 125: } catch (java.lang.Exception e) { 126: throw new java.rmi.UnexpectedException("undeclared checked exception", e); 127: } 128: } 129: } ----------------------------------------------------------------------
---------------------------------------------------------------------- 1: // Skeleton class generated by rmic, do not edit. 2: // Contents subject to change without notice. 3: 4: public final class RemoteCounterObject_Skel 5: implements java.rmi.server.Skeleton 6: { 7: private static final java.rmi.server.Operation[] operations = { 8: new java.rmi.server.Operation("int getValue()"), 9: new java.rmi.server.Operation("void reset(int)"), 10: new java.rmi.server.Operation("void up()") 11: }; 12: 13: private static final long interfaceHash = 5217325697641540004L; 14: 15: public java.rmi.server.Operation[] getOperations() { 16: return (java.rmi.server.Operation[]) operations.clone(); 17: } 18: 19: public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) 20: throws java.lang.Exception 21: { 22: if (opnum < 0) { 23: if (hash == -1068577784738248554L) { 24: opnum = 0; 25: } else if (hash == 2435635625292702899L) { 26: opnum = 1; 27: } else if (hash == 4665897731548305845L) { 28: opnum = 2; 29: } else { 30: throw new java.rmi.UnmarshalException("invalid method hash"); 31: } 32: } else { 33: if (hash != interfaceHash) 34: throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); 35: } 36: 37: RemoteCounterObject server = (RemoteCounterObject) obj; 38: switch (opnum) { 39: case 0: // getValue() 40: { 41: call.releaseInputStream(); 42: int $result = server.getValue(); 43: try { 44: java.io.ObjectOutput out = call.getResultStream(true); 45: out.writeInt($result); 46: } catch (java.io.IOException e) { 47: throw new java.rmi.MarshalException("error marshalling return", e); 48: } 49: break; 50: } 51: 52: case 1: // reset(int) 53: { 54: int $param_int_1; 55: try { 56: java.io.ObjectInput in = call.getInputStream(); 57: $param_int_1 = in.readInt(); 58: } catch (java.io.IOException e) { 59: throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); 60: } finally { 61: call.releaseInputStream(); 62: } 63: server.reset($param_int_1); 64: try { 65: call.getResultStream(true); 66: } catch (java.io.IOException e) { 67: throw new java.rmi.MarshalException("error marshalling return", e); 68: } 69: break; 70: } 71: 72: case 2: // up() 73: { 74: call.releaseInputStream(); 75: server.up(); 76: try { 77: call.getResultStream(true); 78: } catch (java.io.IOException e) { 79: throw new java.rmi.MarshalException("error marshalling return", e); 80: } 81: break; 82: } 83: 84: default: 85: throw new java.rmi.UnmarshalException("invalid method number"); 86: } 87: } 88: } ----------------------------------------------------------------------
Java の標準のセキュリティのポリシー(java コマンドで利用される)は、 jre/lib/security/java.policy に記述されている。 (sakura:/usr/j2se/jre/lib/security/java.policy)
System.setSecurityManager( new RMISecurityManager() ) した時には、 標準よりきつくなる。実験する時には、少し緩めないとつながらない。
以下の例では、IP アドレス(130.158.85.129と130.158.64.20)を修正して使う こと。sakura (130.158.64.20) を使う時には、そのままでもよい。
---------------------------------------------------------------------- // // RemoteCounterServer.policy // grant { permission java.net.SocketPermission "localhost:1024-", "listen,connect,resolve"; permission java.net.SocketPermission "130.158.85.129:1024-", "listen,connect,resolve"; permission java.net.SocketPermission "130.158.64.20:1024-", "listen,connect,resolve"; }; ----------------------------------------------------------------------
---------------------------------------------------------------------- // // RemoteCounterClient.policy // grant { permission java.net.SocketPermission "localhost:1024-", "listen,connect,resolve"; permission java.net.SocketPermission "130.158.85.129:1024-", "listen,connect,resolve"; permission java.net.SocketPermission "130.158.64.20:1024-", "listen,connect,resolve"; }; ----------------------------------------------------------------------クライアント側では、うまく設定すると、サーバ側に置かれたクラスを動的に http や ftp でロードして実行できる。その時には、 java.rmi.server.codebase プロパティを使う。
RMI でオブジェクトを渡す時には、interface Serializable を implements する。
serialize 不要のフィールドには、transient をつける。
serialization は、RMI だけでなく、オブジェクトをファイルに落とす時にも 使える。
Common Object Request Broker Architecture。 OMG (Object Management Group) による ORB。
CORBA の特徴
特徴
例:
---------------------------------------------------------------------- 1: module Counter 2: { 3: interface Counter 4: { 5: void up(); 6: long getValue(); 7: void reset(in long newVal); 8: }; 9: }; ----------------------------------------------------------------------
---------------------------------------------------------------------- % idlj Counter.idl % ls Counter Counter.java CounterHolder.java _CounterStub.java CounterHelper.java CounterOperations.java % ----------------------------------------------------------------------
Counter.idl
を元にして、ディレクトリ Counter/
以下にい
くつかのファイルが作られる。
手続きのインタフェース CounterOperations.java:
---------------------------------------------------------------------- 1: package Counter; 2: 3: 4: /** 5: * Counter/CounterOperations.java 6: * Generated by the IDL-to-Java compiler (portable), version "3.0" 7: * from Counter.idl 8: * Thursday, February 7, 2002 2:56:17 AM JST 9: */ 10: 11: public interface CounterOperations 12: { 13: void up (); 14: int getValue (); 15: void reset (int newVal); 16: } // interface CounterOperations ----------------------------------------------------------------------クライアント側スタブ _CounterStub.java:
---------------------------------------------------------------------- 1: package Counter; 2: 3: 4: /** 5: * Counter/_CounterStub.java 6: * Generated by the IDL-to-Java compiler (portable), version "3.0" 7: * from Counter.idl 8: * Thursday, February 7, 2002 2:56:17 AM JST 9: */ 10: 11: public class _CounterStub extends org.omg.CORBA.portable.ObjectImpl implements Counter.Counter 12: { 13: // Constructors 14: // NOTE: If the default constructor is used, the 15: // object is useless until _set_delegate (...) 16: // is called. 17: public _CounterStub () 18: { 19: super (); 20: } 21: 22: public _CounterStub (org.omg.CORBA.portable.Delegate delegate) 23: { 24: super (); 25: _set_delegate (delegate); 26: } 27: 28: public void up () 29: { 30: org.omg.CORBA.portable.InputStream _in = null; 31: try { 32: org.omg.CORBA.portable.OutputStream _out = _request ("up", true); 33: _in = _invoke (_out); 34: } catch (org.omg.CORBA.portable.ApplicationException _ex) { 35: _in = _ex.getInputStream (); 36: String _id = _ex.getId (); 37: throw new org.omg.CORBA.MARSHAL (_id); 38: } catch (org.omg.CORBA.portable.RemarshalException _rm) { 39: up (); 40: } finally { 41: _releaseReply (_in); 42: } 43: } // up 44: 45: public int getValue () ... 64: public void reset (int newVal) ... 91: private void readObject (java.io.ObjectInputStream s) 92: { 93: try 94: { 95: String str = s.readUTF (); 96: org.omg.CORBA.Object obj = org.omg.CORBA.ORB.init ().string_to_object (str); 97: org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl) obj)._get_delegate (); 98: _set_delegate (delegate); 99: } catch (java.io.IOException e) {} 100: } 101: 102: private void writeObject (java.io.ObjectOutputStream s) 103: { 104: try 105: { 106: String str = org.omg.CORBA.ORB.init ().object_to_string (this); 107: s.writeUTF (str); 108: } catch (java.io.IOException e) {} 109: } 110: } // class _CounterStub ----------------------------------------------------------------------
sakura で問題なく動作したとの連絡が入っている。きちんと元の締切り通り 提出することが望ましい。
次の課題から1つを選んで提出しなさい。問題を難しい方に変えてもよい。締 め切りは、2002/02/13 (水曜日) 18:00 とする。(23:59:59 ではない)。
レポートは、次のような形式の電子メールで送ること。
---------------------------------------------------------------------- To: yas@is.tsukuba.ac.jp Subject: [pdsoft/rmi] <内容に関したサブジェクト> 学籍番号 000000 (各自の学籍番号で置き換える) 名前 漢字の名前 <内容> ----------------------------------------------------------------------