개발을 하면서 IDE의 경고를 유심히 보고 왠만한 것은 처리를 하는 편인데 (대부분을 가이드에 따라서 처리), 전임 개발자의 의도가 있어보이는 코드에 경고문구가 있어 한번 확인을 해보려고 한다.
현재 개발하고 있는 프로세스는 Producer-Consumer 패턴으로 되어있다. 즉 Producer에서는 Consumer가 소비할 데이터를 넣어주고 Consumer는 데이터를 소비하는 형태를 가진다.
Producer와 Consumer의 코드를 보면 다음과 같이 무한 루프로 각 기능을 수행하게 끔 되어있는데, 여기 포함된 Thread.sleep()이 오늘의 주인공이다.
while(isNotInterrupted && handleDataIsRemain) {
/*
- task(work) 수행
Producer: 소비 데이터 큐잉
Consumer: 데이터 소비
*/
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// Handle exception
}
}
위와 같이 코드를 작성하면 IDE에서는 다음과 같은 경고를 준다. “Call to 'Thread.sleep()' in a loop, probably busy-waiting”
Thread.sleep()은 busy-waiting을 만들 수 있으니 자제하라는 경고문이다. 경고문에 대해 이해하기 위해 각 개념에 대해 알아보자
쓰레드의 동작을 일정시간 유예하고, CPU가 다른 작업을 할 수 있도록 허용하는 함수이다. 해당 함수가 실행되면 쓰레드는 TIMED_WAITING 상태로서 일시 정지 상태가되며, 명시한 시간이 지난 후 RUNNABLE을 거쳐 작업실행을 하게 된다.
이 때, sleep전에 가지고 있던 monitor lock은 잃지 않으므로 sleeptime이 지난 후 진행중이던 작업을 바로 실행할 수 있다. 쓰레드를 일시정지 시키면 해당 쓰레드의 CPU 사용이 없어지며 전체 CPU 사용량이 감소할 수 있고, CPU과열 등을 예방할 수 있다.
공유자원의 권한을 얻는 방법중 하나이다. 공유 자원의 경우, 한 시점에 하나의 쓰레드만 접근을 해야 경쟁 상태를 만들지 않기 때문에 이에 대한 방법이 필요하다. 무한 루프를 계속 돌면서 공유 자원의 점유 가능성을 확인하는 방식이 busy-waiting이다.
흔히 말하는 polling 방식의 단점을 가지고 있으므로, 해당 방법보다는 뮤텍스 세마포어를 사용해야 한다.
결국 busy-waiting은 공유자원을 획득하기 위한 방법이며, CPU 사용량을 줄이면서 스케쥴링하기 위한 간단한 방법으로 Thread.sleep()을 생각할 수 있을 것 같다.
이렇게 생각하면 마치 busy-waiting의 대안으로 Thread.sleep()을 사용 할 수 있는 것 처럼 보이기도 한다.
그렇다면 IDE에서 말하는 Thread.sleep()이 아마도 busy-waiting일 것 같다는 것은 어떤 의미일까?? 이는 루프에서의 처리(task)와 sleeptime과 관련이 있다.
멀티쓰레드 환경에서는 많은 변수가 있어 A가 증가하면 B가 증가 혹은 감소한다라고 말할 수는 없지만, task 처리시간에 비해 sleeptime이 작다면 Thread.sleep()으로 인해 쓰레드의 상태를 천이하는 과정에서의 공유자원 상태 확인이 빈번하게 되고 busy-waiting과 유사한 현상이 만들어지게 된다.
결국 Thread.sleep()하다고 busy-waiting이라고 할 수는 없다는 것이 오늘의 결론이 될 것 같다.
위의 Producer-Consumer코드에서 Thread.sleep()을 제거한채로 테스트를 수행한 결과가 이 의견에 더욱 힘을 실어주었다. 테이블 1을 통해 테스트 결과에 대해 알아보자.
sleep time (ms) | CPU user time (%) | Context switches per seconds | TPS |
---|---|---|---|
0 | 81.4 | 129k | 512.8 |
10 | 25 | 60.27k | 671 |
20 | 27 | 44.66k | 680.3 |
테이블 1. sleep time에 따른 CPU 파라미터와 TPS 값
Thread.sleep()이 busy-wating으로서 작용했다면, CPU user time과 Context switches per seconds도 상승하는 경향을 보였을 것이다. 하지만 결과를 보면 sleep time이 증가함에 따라, 두 파라미터의 수치가 오히려 줄어드는 경향을 보이는 것을 확인할 수 있다.
또한 TPS측면에서도 sleep time이 증가함에 따라 TPS가 상승하는 경향을 보였다.