2010-02-18 5 views
4

나는 기본적으로 물리 시뮬레이션을 시각화 한 프로그램입니다. 지금은 작동하지만 매우 반응이 없어 질 수 있습니다. 그리고 왜 - 너무 많은 (읽기 : 모두) 계산이 이벤트 스레드에서 수행됩니다.GUI 응답 속도 향상

'재생'버튼을 누르면 스윙 Timer이 생성되어 주기적으로 깨어나고 updateTime() (지금까지는 매우 양호) 전화가 걸립니다. 문제는 updateTime()이 모든 시간 종속 객체를 반복하고 적절한 시간 (경과 된 실시간 또는 매일 틱 단위의 임의의 시간 단위)으로 정시에 전달하도록 알리는 것입니다. 이러한 계산과 후속 GUI 업데이트는 모두 이벤트 발송 스레드에 있습니다.

그래서이 계산을 가능한 한 많이 오프로드하고 싶습니다. SwingWorker이 최선의 방법이라고 생각합니다. 그러나 기존 코드를 사용하는 방법을 잘 모르겠습니다. 이미 많은 클래스가 이미 다른 클래스를 확장하기 때문에 기존 클래스를 SwingWorker까지 확장 할 수는 없습니다.

지금까지 가장 좋은 생각은 구현할 시간 의존적 개체마다 인터페이스를 만드는 것입니다. 인터페이스는 calcUpdateTime()drawUpdateTime()의 두 가지 메소드를 지정합니다. 현재 updateTime() 메서드를 각각 물리 계산 (calc_)으로, GUI 업데이트 (draw_)로 나눕니다. 그런 다음 생성자에서 TimeDependant 개체를 사용하는 SwingWorker 클래스를 하나만 만들고 그 doInBackgroundcalcUpdateTimedone을 호출하면 drawUpdateTime을 호출합니다. 그럼 나는이 상당히 느낌이 좋지 않기 때문에 SO가이 아이디어를 실행하고 싶었다

new MySwingWorker(myObj, currentTime).execute(); 

myObj.updateTime(currentTime); 

의 모든 항목을 대체 할 수 있으며, 전체 프로젝트를 리팩토링을 피하기 위해 같은 것 다만 나가 나쁜 아이디어로 밖으로 시작했다는 것을 알아 내기 위하여. 또한, 각 틱마다 수십 개의 MySwingWorker을 생성하는 것이 좋지 않은가요?

지금까지 읽어 주셔서 감사합니다.

+0

또한 물리 및 GUI 코드가 함께 혼합되어 있다는 사실을 알고 싶지만 그 결정이 내려지면 주변에 있지 않았기 때문에 아기 단계를 밟고 있습니다. 결국, 두 가지 종류의 코드를 별도의 클래스가 아닌 별도의 메서드로 사용하고자합니다. –

+0

타이머를 사용하면 버튼 클릭 이벤트와 다른 스레드에서 계산을 실행해야합니다. 일반적으로 시나리오에 1 개 이상의 SwingWorker가 필요하지는 않습니다. – sfussenegger

+0

docs (http://java.sun.com/javase/6/docs/api/javax/swing/Timer.html)에 따르면 타이밍은 별도의 스레드에서 발생하지만 ActionEvent는 EDT에서 처리됩니다. –

답변

0

스윙 타이머를 사용하여 성능이 좋지 않았습니다. Swing의 모든 이벤트는 동일한 스레드를 사용하기 때문에 예기치 않은 지연이 많은 것처럼 보입니다.

나는 모든 스틱 작업자 인스턴스에 대해 본능을 믿을 것을 제안합니다. 그것은 나에게도 적절하지 않습니다. (그리고 SwingWorker 문서에 따르면, 한 번만 실행되도록 설계되었으므로 반드시 안전하게 다시 사용할 수는 없습니다.)

필요한 타이머를 수행 할 수있는 타이머는 java.util.Timer입니다. 이것은 타임 아웃을 지정하기위한 많은 옵션을 가지고 있습니다 만, 타이밍 시뮬레이션의 충실도에 따라 적절하지 않을 수도 있습니다. (예를 들어, 실시간으로 실행하고 싶지만 계산이 실제로 실시간보다 오래 걸리는 경우 어떻게해야합니까? 천천히 실행하거나 시간 단계를 건너 뛰시겠습니까?)

calc/draw 루틴이 관련되어 있으므로 임시로 java.util.Timer을 시도해 볼 것을 제안합니다. 만료되면 ("실시간 배율기"에 따라 적절한 시간 제한 기간이 지난 후에) 모든 계산을 실행 한 다음 결과를 다시 EDT 스레드로 보내 드로잉을 수행합니다 (예 : SwingUtilities.invokeLater()).

물론 EDT가 계산 스레드와 동일한 개체를 참조하려는 경우 잠금 문제가 발생할 수 있습니다. 이상 적으로 계산 스레드가 EDT에 결과를 전달할 수 있다면 잠금을 도입하지 않아도됩니다.

(고지 사항 : 위의 어느 것도 GUI 용과 계산 용 이외의 다른 여러 코어/프로세서를 실제로 고려하지 않습니다. 응용 프로그램을 병렬 처리하려면 해당 솔루션이 아닐 수도 있습니다).

+0

그것은 유망 해 보입니다. 나는 이것을 시도하고 그것이 어떻게 작용 하는지를 볼 것입니다. 재 : 멀티 코어/프로세서, 나는 JVM이 그것들을 이용했다고 생각하지 않았다. (적어도 내가 체크 한 마지막 시간에는 내 컴퓨터에서하지 않았다.) –

+0

나는 주로 Sun의 Windows JVM을 사용했고, 다중 코어 (프로세서에 대해서는 확실하지 않음). – Ash

2

정말 싫은 많은 스레드를 만들고 파괴 할 것이기 때문에 모든 틱마다 모든 작업자에게 SwingWorker.execute()을 호출 할 필요는 없습니다.

그러나 SwingWorker을 사용하면 백그라운드에서 실행해야하는 코드 (구현 : SwingWorker.doInBackground())와 실행해야하는 코드를 쉽게 구분할 수 있기 때문에 여전히 좋은 아이디어입니다 나중에 GUI를 업데이트하기 위해 스윙 (SwingWorker.done() 구현).

javax.swing.Timer 또는 java.util.Timer을 사용하는 대신 java.util.concurrent.ScheduledThreadPoolExecutor을 사용하는 것이 좋습니다. 기본적으로 java.util.Timer에서 수행 할 수있는 모든 작업을 수행 할 수 있습니다. 단, 백그라운드에서 작업중인 스레드 수를 제어 할 수있는 기회와 백그라운드 스레드에서 발생하는 예외를 처리하는 방법 등을 제공합니다.