2017-05-21 6 views
1

저는 최근에 내 프로그램에서 가장 비싼 작업 (예 : 객체 marhsalling, 메소드 실행 등)을 식별 할 수 있도록 내 RMI 프로그램에 대한 많은 측정을 수행했습니다. 기본적으로 아래 코드에서 볼 수 있듯이 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

모든 자료
  1. 대수 (2 개 통화)

    • 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 (최상)
    • > 1.874423
    • K = 8 - -> 2.455411
    • K = 16 -> 2.752766
    • K = 32 -> 2.695977

I 또한 내 CPU는 usaged 측정 된 4 =

  • K 각 방법 중에 : 오프셋을 더하기 위해 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; 
    } 
    

    코드 :

    package rmi; 
    
    import java.rmi.RemoteException; 
    import java.rmi.server.UnicastRemoteObject; 
    import java.util.List; 
    
    
    public class ServiceImple extends UnicastRemoteObject implements Service{ 
    
        private static final long serialVersionUID = 1L; 
    
        protected ServiceImple() throws RemoteException { 
         super(); 
        } 
    
    
        @Override 
        public float[] log(float[] vector, int vSize, int base) throws RemoteException { 
         for (int i=0; i<vSize; i=i+1){ 
          vector[i] = (float) (Math.log(vector[i])/Math.log(base)); 
         } 
         return vector; 
        } 
    
        @Override 
        public float[] addOffset(float[] vector, int vSize, int offset) throws RemoteException { 
         for (int i=0; i<vSize; i=i+1){ 
          vector[i] = vector[i] + offset; 
         } 
         return vector; 
        } 
    } 
    
    ,515,
  • +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 런타임은 원격 객체 호출을 스레드에 매핑하는 것과 관련하여 어떠한 보증도하지 않습니다.

    적어도 하나의 스레드에서 RMI 요청이 실행된다는 보장은 없습니다. 실제로 우리가 보는 것은 표준 Java RMI 구현이 요청을 처리하기 위해 다중 스레드를 사용한다는 것입니다.

    1

    서버가 단일 스레드인데도 클라이언트의 다중 스레드가있는 Java RMI가 더 빠른 이유는 무엇입니까?

    귀하의 가정은 거짓입니다. RMI 서버는 단일 스레드가 아닙니다.