並列分散ソフトウェア
電子・情報工学系
新城 靖
<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)で殺す。---------------------------------------------------------------------- % iduid=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 (各自の学籍番号で置き換える) 名前 漢字の名前 <内容> ----------------------------------------------------------------------