프로덕션 코드에서 스레드를 유휴 상태로 만들어서는 안 된다

 

프로덕션 코드에서 Thread.Sleep()을 사용하지 마라.

 

Thread.Sleep() 정적 메소드는 현재 스레드를 유휴 상태로 만드는데, 주어진 시간 동안 운영체제로 하여금 현재 스레드에 시간을 할당하지 않게 된다. 밀리초 단위의 숫자 혹은 TimeSpan 형식의 매개변수를 통해서 실행을 재개하기 전에 운영체제가 대기해야 할 시간을 지정한다. 대기하는 동안에 운영체제는 대기 중인 다른 스레드에 시간을 할당한다. 꽤 그럴듯하게 들리지만 이런 상황에 대처하기 위한 더 나은 설계가 있을 것 같은 나쁜 코드 냄새가 난다.

 스레드는 종종 여러 이벤트와 보조를 맞추려고 유휴 상태에 놓이곤 한다. 하지만 운영체제는 이와 관련된 시점 조절과 관련해 정확성을 일체 보장하지 않는다. , ‘123 밀리초 동안 유휴 상태로 유지해 주세요라고 요청했을 때, 운영체제는 해당 스레드를 적어도 123 밀리초 동안 유휴 상태로 만드는 데 훨씬 더 오래 걸릴 가능성도 있다. 스레드가 유휴 상태로 진입하고 또 벗어나는 데 걸리는 시간은 절대적인 것이 아니며 임의의 시간이 소요될 수 있다. Thread.Sleep()을 고정밀 타이머처럼 사용해서는 안 되는 이유다.

 더 심한 경우는 Thread.Sleep()바보들의 동기화 시스템으로 사용하는 것이다. 예를들어 일정량의 비동기 작업을 수행해야 하고 이 비동기 작업이 끝나기 전에는 현재의 스레드를 더 이상 진행해서는 안 되는 상황을 가정해 보자. 이때 비동기 작업이 끝날 것으로 예상되는 대략적인 시간보다 충분히 더 여유를 잡아서 스레드를 유휴 상태로 만들고 스레드가 유휴 상태에서 깨어났을 때 비동기 작업이 끝났을 것이라는 위험한 가정을 기준으로 개발을 시도할 수 있다. 이것은 정말 위험한 생각이다. 비동기 작업은 여러분이 생각하는 것 보다 더 긴 시간을 요할 수 있다. 이와 같은 상황에 적합한 스레드 동기화 메커니즘을 다음 장에서 살펴본다.

 스레드를 유휴 상태로 만드는 것 자체도 나쁜 프로그래밍 습관이라고 볼 수 있다. 일단, 스레드가 유휴 상태에 들어가면 스레드에서 포함하고 있는 코드는 원해도 실행할 수 없는 무응답 상태가 되기 때문이다. 윈도우 응용 프로그램의 주 스레드를 유휴 상태로 만들면 사용자 인터페이스에서 발생하는 메시지도 처리하지 않게 되기 때문에 결국 프로그램은 응답이 없는 상태에 빠진다.

 더 일반적인 시각에서 보면 스레드와 같은 값비싼 리소스를 할당해 놓고 작업을 하지 않게 하는 것은 역시 바람직한 프로그래밍이 아니다. 아무도 잠만 자는 직원에게 월급을 주지 않으려 할 것 이다. 따라서 수백만이나 수십억에 이르는 프로세서 주기를 허송세월로 흘려보내려고 힘들게 스레드를 할당하지 않는 것이 바람직하다.

 한편, Thread.Sleep()을 적절하게 사용하는 경우도 물론 있다. 유휴 대기 시간을 0으로 설정해 호출하는 방식으로, 운영체제에게 남아있는 시간 할당을 포기할 의사를 전달해서 대기 중인 다른 스레드로 순서를 재빨리 넘기도록 할 수 있다. 이렇게 양보한 스레드는 추가적인 대기 시간 없이 다시 일반적인 스케줄에 따라 작업을 진행한다. 다음으로 테스트 코드에서는 종종 실제로 프로세서에 의미 없는 연산을 시켜 부하를 주는 방법 대신 Thread.Sleep()을 이용해서 일부 장기간의 대기 시간을 요하는 작업을 모의하기도 한다. 다른 이유로 스레드를 유휴 상태로 만들고 있다면 원하는 기능을 구현할 수 있는 더 좋은 방안이 없는지 조심스럽게 검토해 보는 것이 좋다.

 C# 5.0의 태스크 기반 비동기 프로그래밍에서는 Task.Delay() 메소드의 결과에 await 연산을 이용해서 현재 스레드의 진행에 영향을 주지 않고 비동기 지연 처리가 가능하다. 자세한 내용은 다음 장의 타이머 절을 참고하라.

 

 

 - Essential C# 5.0 (C#의 기초와 고급을 아우르는 핵심 바이블) - 18장 다중 스레딩

 

+ Recent posts