2006의 게시물 표시

자바에서의 File IO 성능

파일을 읽고 쓰는 것은 프로그래밍에서 아주 빈번하게 발생하는 일이다.

일반적인 통념 상 파일 시스템은 네트웍에 비해 훨씬 빠르고 메모리에 비해 훨씬 느리다. 보통 그 성능 비율은 100 정도로 유지가 되고 있다.

파일을 읽고 쓸 때의 성능을 보장하려면 다음 몇 가지 부분을 염두에 둬야 한다.

file open/close 가 빈번하게 발생하면 성능에 나쁜 영향을 미친다. output stream flush가 빈번하게 발생하면 성능에 나쁜 영향을 미칠 수 있다. (file의 경우 윈도우에서는 거의 영향이 없었고, 리눅스의 경우 큰 영향이 있었다.) stream io와 channel io를 단순 비교하면 stream io 성능이 오히려 나은 경우가 대부분이다.buffered io를 사용하면 어느 정도의 성능 개선 효과를 보인다. (리눅스 output stream의 경우 아주 큰 개선 효과. 다른 경우에도 조금의 성능 개선 효과. 물론 최적의 buffer 크기를 잘 선택하는 것이 중요하다.) memory map io를 사용하는 것이 단연 가장 빠르다. 심지어 1k 미만의 파일을 읽을 때도 더 빠르다.

Calendar is too slow

java.util.Calendar 객체를 생성하는 데는 상당한 비용이 소요된다.

즉,


Calendar.getInstance()


라는 메소드를 호출하여 Calendar 객체를 가져오는 데 걸리는 시간이 상당하다.


// 현재 시간을 가져오는 보통의 방법
private static Calendar getCalendar1() {
return Calendar.getInstance();
}

// 현재 시간은 아니지만 Calendar 객체를 clone을 통해 가져오는 방법
private static Calendar getCalendar2() {
return (Calendar) cal.clone();
}

// Calendar 객체를 clone을 통해 가져와서 현재 시간으로 만드는 방법
private static Calendar getCalendar3() {
Calendar c = (Calendar) cal.clone();
c.setTimeInMillis(System.currentTimeMillis());
return c;
}

// 가장 범용적인 GregorianCalendar 객체를 직접 생성하는 방법
private static Calendar getCalendar4() {
Calendar c = new GregorianCalendar();
return c;
}


위의 메소드를 약 10만회씩 실행한 결과는 다음과 같다.


// JDK 1.4

it took 391 (ms)
it took 187 (ms)
it took 375 (ms)
it took 328 (ms)

// JDK 1.5

it took 469 (ms)
it took 266 (ms)
it took 421 (ms)
it took 344 (ms)


JDK 1.4와 1.5 모두 그냥 Calendar 객체를 clone을 통해 만드는 것이 가장 …

Business Process Management Solution, Tmax BizMaster

비즈니스 마스터라는 이름이 얼마나 어울리는지는 모르겠다.

업무를 프로세스 기반으로 관리한다는 것은 흐름 제어과 그 수행에 대한 분석을 통한 feedback을 포함한다.

C, C++, Java, ... 코딩을 해야지, 프로세스라니...

하는 생각도 많이 한다. 자바 코더로 자바 코딩보다 더 빠르고 편한 게 있을 리가...

어쨌든 BPM은 업무를 자동화해주고 그에 기반하여 업무를 수행하면 그 결과를 관심에 맞춰서 분석하여 알려준다.

세상에 존재하는 다종다양한 업무 패턴을 모아서 워크플로우 패턴 (http://www.workflowpatterns.com) 이라는 사이트를 Wil van der Aalst 라는 네덜란드 교수가 운영한다.

아알스트는 상당히 워크플로우와 BPM에서는 유명한 교수인데, BPM은 BPEL(BPEL4WS 혹은 WS-BPEL)이나 BPML이라는 XML로 정의된 웹 서비스 기반 프로세스로 구축할 수 있다는 분위기가 한창이던 2004년 쯤에 업무 패턴을 실행 못하면 BPM이 아니라는 논지로 반박하면서 워크플로우의 프로세스 엔진 기능의 중요성을 강조했었다.

이 사상에 기반한 BPMN이라는 업무 흐름 표기법이 이맘때쯤 등장했고, BPMN은 지금 OMG에서 표준화 과정을 거치고 있어 업계 표준으로 확고히 자리잡을 전망이다.

티맥스소프트는 필자가 근무하는 회사이다.
그리고 비즈마스터는 필자가 직접 만들고 있는 BPM 제품이다.

"내가 만든 제품이 최고입니다" 이런 말을 하고자 하는 것은 아니다.

하지만, 비즈마스터는 워크플로우 패턴의 사상을 충실히 반영하고 있는 전용 프로세스 엔진에 기반하고 있는 세계 최초의 제품 중 하나이다.
물론, 비즈마스터는 BPEL 엔진도 포함하고 있다.

블럭 모듈 방식의 프로세스 처리를 채택하고 있는 BPEL이나 BPML 같은 프로세스 언어와 단방향 그래프 방식에 기반하고 있는 BPMN 같은 사상은 근원적인 차이를 가지고 있다.
이를 무시하고 이 두 가지 서로 다른 프로세스 처리 방법을 동시에 처리하려는 시도가 몇 있었다.

국내 ope…

컴파일할 때, 뭘 하나요...

개발자들의 업무 효율과 관련해서 asynchronous event를 제거하는 것의 중요성은 software development team manager에게 매우 중요한 일이다.

개발은 집중을 요구하는데 context switching 혹은 집중으로부터 벗어나는 계기가 되는 일들이 가끔 있다.

메신저류들, 혹은 메일 notification 등등...

그러한 것들 외에도 습관적인 부분들이 존재한다.

컴파일이 시간이 걸릴 경우 혹은 테스트하기 위해 패키징하는 시간이 걸리는 경우, 테스트를 위해 서버 같은 테스트 환경을 부팅 시키는 데 시간이 걸리는 경우 등등 코딩의 연속성을 벗어나게 되는 일들이 있다.

이때 무엇을 하느냐에 따라 개발 효율이 많이 떨어지게 된다.

컴파일하는 동안 잠시 신문을 읽는다든지 웹 서핑을 한다든지 한다면 이 상황에서는 다시 원래의 집중으로 회복하는 데 최소 30분이 소요된다.
이러한 경우에는 컴파일 몇 번 돌리면 하루가 다 가게 된다.

컴파일하는 도중에 계속해서 같은 문맥의 코딩을 할 수 있다면 가장 좋다.
그것이 안된다면, 이러한 때를 위한 가벼운 읽을거리를 마련해두자. 연예정보가 아닌 개발에 필요한 정보를 습득할 수 있는 거리를.. (적어도 뇌의 같은 부위를 사용하는 일을 하도록 해서 context switching이 발생하지 않도록 .. ^^;;)
잠시 호흡을 가다듬는다거나, 뇌를 쉬게 하는 것도 좋다.

불필요하게 뇌를 다른 문맥에서 헤매게 노동시키는 것을 경계하면 된다.
^^;;

serialVersionUID 기본 알고리즘

자바에서 serial version uid를 생성하는 것은 기본적으로 서로 다른 클래스들 간의 구별을 하기 위한 것이다.
동일한 이름을 가진 클래스라 하더라도 메소드나 필드가 다를 경우 서로 다른 것으로 인식하는 것이 기본이기 때문에 Object Serialization을 할 때 import/export 등에서 버전에 따라 종종 불일치 에러가 발생하는 것을 만나게 된다.

클래스가 바뀌었다는 것을 기본 serial version uid 계산 알고리즘을 통해서 검출했기 때문이다.
물론
private static final long serialVersionUID = -6120832682080437368L;
와 같이 클래스에 직접 serial version uid 값을 지정해버리면 기본 uid 계산 알고리즘을 사용하지 않고 이 값을 사용하게 되므로 버전에 따른 불일치 에러는 막을 수 있다.

이렇게 하지 않은 경우 사소한 메소드 시그너처 변경으로도 불일치가 발생하게 된다.

기본 uid 값 계산에 사용되는 정보들은 다음과 같다.

1. 클래스 이름 (fully qualified)
2. 클래스의 접근 제한자 (public, final, abstract, 또 interface 여부)
3. 각 멤버 필드의 시그너처 (이름과 접근 제한자, 타입)
4. 각 멤버 메소드의 시그너처 (이름과 접근 제한자, 각 인자별 정보, 리턴 타입)
4. 각 생성자의 시그너처 (접근 제한자, 각 인자별 정보)
5. static initializer block 존재 유무

이러한 값들을 사용하여 적당한 문자열을 만든 다음 SHA 알고리즘을 사용하여 해시값을 계산한 값이 기본 UID 값이 된다.
이때 필드나 메소드, 생성자의 선언 순서는 바뀌더라도 상관없도록 sort를 한다음 계산을 한다.

여기에서 알 수 있듯이 사소한 변경만으로도 기본 suid 값은 변경되게 마련이다.
따라서 serializable 객체로 객체 통신에 사용되는 클래스들은 가능하면 명시적으로 suid 값을 지정해주는 것이 버전 관리의 문제를 피할 수 있는 가…