2017-05-21 7 views
1

最近私のプログラムで最も高価な操作(例えば、オブジェクトのマーシャリング、メソッドの実行など)を特定するために、RMIプログラムの最近の測定をたくさん行ってきました。基本的には、以下のコードからわかるように、私は3つの遠隔操作にパラメータとして渡すことができるfloat配列を持っています:すべての要素のパワー(すべての要素の)、すべての要素のベースにログインし、すべての要素)。配列のサイズはN = 10^8です。サーバがシングルスレッドであっても、クライアント上の複数のスレッドを持つJava RMIが高速になるのはなぜですか?

私のクライアントはマルチスレッド(Kスレッド)であり、配列をN/Kに分割し、各チャンクをスレッドに渡します。各スレッドはRMI呼び出しを呼び出します。サーバーは純粋にシングルスレッドです。クライアントとサーバーは同じマシン上で実行されています。

クライアント・スレッドの数がK = 1,2,4,8,16,32の場合、これらの各メソッドが戻るまでの時間は次のとおりです(IN SECONDS - 10回のサンプリング - マシン:i7 quad-コア(8つの論理プロセッサ)):任意の塩基(Math.log 2つのコール)で

  1. 対数:

    • K = 1 - > 7.306161
    • K = 2 - > 3.698500
    • K = 4 - > 2.788655
    • K = 8 - > 2.679441 (最良)
    • K = 16 - > 2.754160
    • K = 32 - > 2.812091
  2. 合計オフセット(単純和、他のメソッドへの呼び出しありません):

    • K = 1 - > 3.573020
    • K = 2 - > 1.864782 (最良)
    • K = 4 - > 1.874423
    • K = 8 - > 2.455411
    • K = 16 - > 2.752766
    • K = 32 - > 2.695977

私もCPUを測定usaged各方法の間:オフセットを加えるために、CPU使用率はほとんどの場合約60%でしたが、対数メソッド呼び出しはCPUの80%以上を必要とし、100%を複数回ピークに達しました。私も(下のコードから抜粋した)パワーメソッドを試してみました。オフセットを追加すると非常に似た結果を示しました。

オフセットを追加するのが超安価であるため、スレッドをさらに処理すると、スレッドスケジューリングなどのためにコストが高くなるという結論は簡単です。そして、対数の計算はより高価なので、スレッド数が増えるほど問題が早くなります。そのため、8台のCPUを搭載したマシンではK = 8が最適です。

ただし、サーバーはシングルスレッドです。どのようにこれを可能にすることができますか?どのように8クライアントスレッドは、この状況で2クライアントスレッドよりもはるかに優れた仕事をすることができますか?

私はこれらの結果について考えるのに苦労しています。どんな助けもありがとうございます。各モジュールのコードを以下に示します。

Server.javaのためのコード:Client.javaため

package rmi; 

import java.rmi.Naming; 
import java.rmi.Remote; 
import java.rmi.registry.LocateRegistry; 

public class Server { 

    Server(){ 
     try { 
      System.setProperty("java.rmi.server.hostname", "localhost"); 
      LocateRegistry.createRegistry(1099); 
      Service s = new ServiceImple(); 
      Naming.bind("Service", (Remote) s); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String[] args){ 
     new Server(); 
    } 
} 

コード:Service.javaため

package rmi; 

import java.rmi.Naming; 
import java.util.ArrayList; 

public class Client { 

    private static final int N = 100000000; 
    private static final int K = 64; 
    private static final int iterations = 1; 



    public static void main(String[] args) throws InterruptedException { 

     //Variable to hold current pseudo-random number: 
     final int a = 25173; 
     final int b = 13849; 
     final int m = 3276; 

     int x = m/2; 

     //Create a list of lists: 
     ArrayList<float[]> vector = new ArrayList<>(); 

     for (int i=0; i<K; i++){ 
      vector.add(new float[N/K]); 
      for (int j=0; j<N/K; j++){ 
       x = (a * x + b) % m; 
       vector.get(i)[j] = (float) x/m; 
      } 
     } 

     long startTime = System.nanoTime(); 

     for (int count=0; count<iterations; count++){ 

      //Creates the list of threads: 
      ArrayList<ClientThread> threads = new ArrayList<>(); 

      //Starts the threads 
      for (int i=0; i<K; i++){ 
       threads.add(new ClientThread(vector.get(i), N/K)); 
       threads.get(i).start(); 
      } 

      //Waits for threads to end: 
      for (int i=0; i<K; i++){ 
       threads.get(i).join(); 
      } 

     } 

     long estimatedTime = System.nanoTime() - startTime; 

     estimatedTime /= iterations; 

     System.out.println("Each loop took: "+(float)estimatedTime/1000000000); 
    } 

} 


class ClientThread extends Thread{ 

    private float[] vector; 
    private int vSize; 

    public ClientThread(float[] vectorArg, int initSize){ 
     vector = vectorArg; 
     vSize = initSize; 
    } 

    @Override 
    public void run(){ 
     try { 
      Service s = (Service) Naming.lookup("rmi://localhost:1099/Service"); 

      //Calculates log in RMI: 
      //vector = (float[]) s.log(vector, vSize, 2); 

      //Adds an offset in RMI: 
      vector = (float[]) s.addOffset(vector, vSize, 100); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

コード:ServiceImple.javaため

package rmi; 

import java.rmi.Remote; 
import java.rmi.RemoteException; 
import java.util.List; 

public interface Service extends Remote { 

    //Return log in parameter base of all elements in vector: 
    public float[] log(float[] vector, int vSize, int base) throws RemoteException; 

    //Adds an offset to all elements in vector: 
    public float[] addOffset(float[] vector, int vSize, int offset) throws RemoteException; 
} 

コード:

​​ の
+1

サーバーがシングルスレッドであることをどのように判断しますか? –

+0

私はそれが何か異なるものであるための機能を追加しませんでした。私はそれがそうであると仮定している。 – Denolth

+3

@Denolth各クライアントのリクエストは別の接続スレッドで実行されるため、サーバーをシングルスレッド化するために何かする必要があります。そうしないと、マルチスレッド化されます。サービスメソッドへの同期を追加するか、プロパティ 'sun.rmi.transport.tcp.maxConnectionThreads'を指定します。詳細はhttps://docs.oracle.com/javase/8/docs/technotes/guides/rmi/sunrmipropertiesを参照してください。 html –

答えて

2

RMI specification 3.2状態:

または別のスレッドで実行してもしなくてもよいリモートオブジェクトの実装にRMIランタイムによって送出方法。 RMIランタイムは、リモートオブジェクト呼び出しをスレッドにマッピングすることに関して保証しません。

少なくとも、1つのスレッドでRMI要求が実行される保証はありません。 実際には、標準のJava RMI実装では複数のスレッドを使用してリクエストを処理しています。

1

サーバがシングルスレッドであっても、クライアント上の複数のスレッドを持つJava RMIが高速になるのはなぜですか?

あなたの前提はfalseです。 RMIサーバはシングルスレッドではありません。

関連する問題