2009-12-30 3 views
3

가정하자 내가 좋아하는 자바 방법이 있습니다사전 생성 객체는

public Ouput respond(Input input) { /* .. */ } 

Output 개체가 많은 분야가 있습니다 - 이러한 필드 중 일부는 Input 객체에 의존하지만, 나머지는 미리 결정된다. 가능한 한 빨리 반환하기 위해 respond()을 호출하는 스레드를 만들고 싶습니다. 내가 다른 스레드 산란 할이 들어

, Output 객체를 사전이 만들어집니다 일부 필드를 설정하고 respond()를 실행하는 스레드가 대기열에서 선택할 수 있도록 대기열에두고, 나머지 필드 및 반환을 설정 그것.

이와 비슷한 것을 구현하는 가장 좋은 방법은 무엇입니까? 내 현재 프로토 타입은 한정된 LinkedBlockingQueue을 사용하지만이 아이디어를 구현하는 더 좋은 방법이 있습니까?

내 목표는 최대한 빨리 respond() 방법을 얻는 것입니다. 따라서 그 목표를 충족시키는 다른 제안도 환영합니다. :-)

+1

메소드를 최적화하는 데 도움이되도록 'Output' 클래스의 코드를 살펴야합니다. 우리가 말하는 분야가 무엇인지 아는 것이 중요합니다. (나는이 말을하기 때문에 필드의 묶음에 대한 기본값으로'Output'의 인스턴스를 만드는 것이 시간 집약적 인 프로세스가 아닙니다 ...) – delfuego

+0

@delfuego 위의 코드를 작성했습니다; 실제 코드는 더 복잡하지만 테스트/프로파일 링은 객체 구축 오버 헤드가 중요하다는 것을 나타냅니다. 'Output' 클래스는 제 3 자 라이브러리에 있습니다.이 라이브러리는 내가 액세스 할 수없는 소스입니다. –

+0

배열이 아닌 링크 된 이유는 무엇입니까? 나는 ArrayBlockingQueue가 LinkBlockingQueue보다 약간 더 나은 성능을 보일 것이라고 가정한다. 배열 구현에는 링크 객체를 유지 관리하는 추가 오버 헤드가 없기 때문이다. – Suppressingfire

답변

2

아마도 respond() 호출마다 Output 객체를 만들지 않아도되지만 더 이상 필요하지 않은 Output 객체는 재활용 할 수 있습니다. 필드를 재설정하는 것은 처음부터 새로 작성하는 것보다 빠르며, 객체 처리량이 높으면 가비지 콜렉션에 시간을 절약 할 수 있으며 프로세서 및 Java VM의 캐시 성능을 향상시킬 수도 있습니다.

물론 이것은 전체 프로세스를 제어 할 수 있고 respond()의 결과를 얻는 호출자를 변경할 수있는 경우에만 작동합니다.

그러나 실제로 이러한 높은 성능 요구 사항이있는 경우이 문제를 해결할 수있는 또 다른 아이디어 일 수 있습니다. 더 이상 유지 보수하기가 너무 복잡하지 않도록하십시오.

+0

@ Kosi2801 불행히도, 나는 만든 개체의 수명주기를 제어 할 수 없어 내 경우에는 개체 풀링이 쉽지 않을 수 있습니다. 그럼에도 불구하고, 그것은 내가 생각해야 할 어떤 것입니다 - 가져와 주셔서 감사합니다! –

3

FutureExecutor을 잘 활용할 수있는 것과 같습니다. 자세한 내용은 여기를 참조하십시오 : 여기

  • http://java.sun.com/javase/6/docs/api/java/util/concurrent/Future.html
  • http://java.sun.com/javase/6/docs/api/java/util/concurrent/Executor.html는 구체적인 예입니다 : 귀하의 경우

    ExecutorService executor = Executors.newSingleThreadExecutor(); 
    
    final Input input = ... 
    Future<Output> future = executor.submit(new Callable<Output>() { 
        public Output call() { 
        return respond(input); 
        } 
    }); 
    
    // do some work 
    
    Output output = future.get(); // this blocks until it's done 
    

    , 당신은 Output 객체의 필드의 일부임을 언급 이후 다른 것들은 나중에 사용되지만, 여러분은 Output 객체를 conta로 구조화 할 수 있습니다 선물 분야에서. 예를 들어 :

    public Output respond(final Input input) { 
        Output output = new Output(); 
        String fieldA = ... 
        output.setFieldA(fieldA); 
    
        Future<String> fieldBFuture = executor.submit(new Callable<String>() { 
        public String call() { 
         String fieldB = ... 
         return fieldB; 
        } 
        } 
    
        output.setFieldB(fieldBFuture); 
    } 
    

    을 그리고 당신의 Output 개체 사용 :

    public class Output { 
        private String fieldA; // immediate field 
        private Future<String> fieldB; // delayed field 
    
        public void setFieldA(String fieldA) { this.fieldA = fieldA; } 
        public String getFieldA() { return fieldA; } 
        public void setFieldB(Future<String> fieldB) { this.fieldB = fieldB; } 
        public Future<String> getFieldB() { return fieldB; } 
    } 
    

    당신은 다음과 같이 당신의 응답 방법을 구성하려는 필드의 나머지 부분은 진정 경우

    Input input = ... 
    Output output = respond(input); 
    
    String fieldA = output.getFieldA(); 
    // do some work 
    String fieldB = output.getFieldB().get(); 
    
+1

@toluju 나는 Executor가이 상황에서 어떻게 유용 할 수 있는지 이해하지 못했다. 알고리즘을 요약 해 주시겠습니까? –

+0

@binil 당신을위한 예제가 추가되었습니다. – toluju

+0

toluju, binil 위에서 언급 한'Output'은 소스 액세스 권한이없는 타사 라이브러리에 의해 제공됩니다. 이 방법은 그가 할 수없는 클래스를 수정할 수 있어야한다고 생각합니다. – delfuego

0

을 "pre-determined"왜 Output 클래스에서 정적으로 만들지 않습니까?

+1

"미리 결정된"이란 말은 "Input"에 의존하지 않고 모든 사람이 respond()를 호출하기 전에 결정될 수 있음을 의미합니다. –

+0

respond() 호출이 서로 다른가요? –

1

건설중인 경우 Output 개체의 내부 저장소를 미리 채우고 요청시 해당 개체를 채우고 내부 저장소를 다시 채울 필요가있을 때를 알 수있는 논리를 포함하는 개체 생성 팩토리를 만드는 것이 어떨까요? 아마도 이것과 같은 것입니다. (이것은 단지 머리 중심의 단순 코드에 불과하며, 풀이 너무 적은 객체를 결정할 수있는 특정 알고리즘을 가지고있는 것처럼 더 많은 일을 할 수있는 명확한 장소가 있습니다. 다시 채우기 등)에 모든 스레드가 같은 힙을 공유하고 있기 때문에

public class OutputFactory { 

    private List<Output> outputPool = new LinkedList<Output>(); 

    public OutputFactory() { 
     this.populatePool(); 
    } 

    private void populatePool() { 
     // spawn a new thread here, if you wish, to optimize time-to-return 
     for (int i = 0; i < 100; i++) { 
      outputPool.add(new Output()); 
     } 
    } 

    public Output getNewOutput() { 
     Output newOutput = outputPool.remove(0); 
     if (outputPool.size() < 10) { 
      populatePool(); 
     } 
     return newOutput; 
    } 

} 
+1

이것은 풀을 다시 채워야 할 때마다 100 번째 요청을 차단합니다. 의도 한 동작이 아닙니다.아마도 Asker가 출력 생성을위한 다른 스레드를 참조하는 이유 인 것 같습니다. 따라서 모든 요청()은 100 개에서 99 개가 아닌 최대한 빨리 반환됩니다. – Kosi2801

+0

Kosi2801, 이것이 내가 새 메시지를 생성 할 수 있다고 말한 이유입니다. 원한다면 거기에 스레드하십시오. 나는 전체 아이디어를 전달하기 위해 의사/단순 코드로 작성했습니다. – delfuego

+0

죄송합니다. 간과했습니다. – Kosi2801

1

, 나는 다른 스레드를 생성하는 것은 지금까지 할당에 관한 한 많은 차이를 만들려고하고 있다는 것을 상상할 수 없다. 스레딩의 이점이 있다면 출력 개체에 미리 정의 된 필드를 설정하는 데 필요한 계산이 필요하기 때문일 수 있습니다.

그럴 경우 미리 지정된 필드가있는 단일 템플릿 출력 개체를 미리 작성한 다음 respond() 공유 템플릿 개체를 복제하면됩니다. 객체가 아직 Cloneable이 아니며 그렇게 만들 수없는 경우 필드 자체를 복사하는 데는 거의 같은 비용이 소요됩니다.

템플릿이 작동하지 않지만 Output 인스턴스를 재사용 할 수있는 경우, 새로운 메모리를 전혀 할당 할 필요가 없으며 미리 정해진 필드를 복사 할 필요가 없기 때문에 아마 더 좋은 옵션 일 것입니다. 그들은 이미 설정 될 것입니다.

이러한 전략 중 하나를 사용하면 별도의 스레드 오버 헤드없이 respond() 메서드의 속도를 높일 수 있습니다.

+0

@benzado 당신은 할당량이 어느 스레드에 관계없이 동일한 양의 시간이 걸릴 것이라고 생각합니다. 이전에 할당을 수행하여 respond() 메소드의 인식 된 성능을 향상 시키려고합니다. 패스트 푸드 레스토랑과 같다고 생각하십시오. 요리 시간에 상관없이 음식을 조리하는 데 걸리는 시간은 동일하지만, 조리 된 음식을 미리 먹는다면 고객은 더 빠른 서비스를 인식합니다. –

+0

"인식 된"성능은 아니며 성능을 향상시키려는 대기 시간입니다. 어쨌든, 내가 제안한 두 가지 방법 모두 도움이 될 것입니다. – benzado

2

출력 필드에서 사용되는 개체를 만드는 것이 비용이 많이 들지 않으면 다른 스레드를 사용하는 데 드는 비용이 몇 필드를 설정하는 것보다 몇 배 더 큽니다.