저는 최근에 내 프로그램에서 가장 비싼 작업 (예 : 객체 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
모든 자료대수 (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
합계 오프셋 (단순 합 다른 방법에는 호출되지)
- 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 =
옵셋을 추가하는 것이 매우 저렴하므로 더 많은 스레드를 처리하는 것이 스레드 스케줄링과 모든 이유로 인해 더 비싸다고 결론 지을 수 있습니다. 그리고 로그를 계산하는 것이 더 비싸므로 더 많은 스레드가 문제를 더 빨리 만들어 내며, 따라서 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,
서버가 단일 스레드인지 어떻게 알 수 있습니까? –
다른 기능을 추가하지 않았습니다. 나는 그러므로 그것을 추측하고있다. – Denolth
@Denolth 각 클라이언트 요청은 별도의 연결 스레드에서 실행되므로 서버를 단일 스레드로 만들려면 무언가를해야합니다. 그렇지 않으면 다중 스레드가됩니다. 서비스 메소드에 동기화를 추가하거나 'sun.rmi.transport.tcp.maxConnectionThreads'속성을 지정하십시오. 자세한 내용은 여기 (https://docs.oracle.com/javase/8/docs/technotes/guides/rmi/sunrmiproperties)를 참조하십시오. html –