Genius DM

C# > ThreadPool Basic 본문

.NET

C# > ThreadPool Basic

Damon Jung 2018. 8. 20. 09:37

ThreadPool


System.Threading 네임스페이스에 속한 클래스로, 쓰레드 풀을 제공한다. Pool 은 영어 의미적으로 한 눈에 볼 수 있는 어떤 공간 ( 주로 사각형 ) 의 내용물을 의미한다. 그 내용물이 물이면 Swimming Pool 로 수영장이 되고, 당구공이 있으면 Pool Table 이 되어 당구대가 된다. Pool 은 그런 느낌이다.


고로 ThreadPool 이면, Thread 가 컨텐츠로 있는 공간을 의미하는 것이다. 이 ThreadPool 을 이용해서 비동기 I/O 작업을 할당하거나 특정 작업을 Thread 를 통해서 실행시킬 수 있다.




ThreadPool 의 장점

    • 미리 생성된 Thread 를 사용하여 비용이 많이 드는 Thread 생성 작업을 생략할 수 있다.
    • ThreadPool API 를 통해서 Delegate 를 Queue 에 넣어두면 ThreadPool 이 알아서 사용 가능한 Thread 에 작업을 할당한다.
    • 작업 할당 뿐만 아니라 Thread 생성 / 소멸의 생명주기 관리를 자동으로 해준다.
    • Thread 가 더 필요한 경우가 생기면 자동으로 ThreadPool 의 Thread 수를 증가시킨다. 그 반대도 마찬가지이다.


ThreadPool 의 단점

    • 가볍고 빠르게 완료할 수 있는 작업에 최적화 되어있다. 
    • 1 초 이상이 걸리는 작업이라면, 별도 Thread 를 생성하는 것이 나을 수 있다.
    • TPL ( Task Parallel Library ) 와는 다르게 작업을 대기 하거나 작업을 취소할 수 없다.
    • Queue 에서 FIFO 방식으로 작업이 할당되어 중요도 순서로 작업을 오더링할 수 없다.



ThreadPool 예제

ThreadPool 의 간단한 예제를 보자.


ThreadPool.QueueUserWorkItem(LightweightThread) 를 통해서 static void 함수가 delegate 로 전달되었다. ThreadPool 에서 이제 해당 delegate 를 Thread 에 할당하여 작업을 시작 후 작업이 종료되면 다시 Thread 를 대기 상태 ( Sleeping ) 로만들어 새로운 요청을 받을 수 있게 만든다. 기본적이고 ThreadPool 에 등록된 Thread 를 Queue 에서 Dequeue 할 때 마다 "대여" 한다고 생각하면 편하다.

Quiz

만약 Thread.Sleep(1000) 을 지우면 어떻게 될까?

=> Main() 의 Main thread 가 ThreadPool 의 Thread 가 static void 함수를 실행하기 전에 종료되어 버린다. ThreadPool 은 백그라운드 쓰레드를 사용하므로 상위 쓰레드가 소멸되어 버리면 ThreadPool 의 Thread 는 할당된 delegate 를 더 이상 실행할 수 없게 된다.






ThreadPool 을 사용하게 되는 경우

위와 같이 명시적으로 ThreadPool API 를 통해서 ThreadPool 을 이용하는 경우가 있고, 개발자가 미처 깨닫지 못 하는 사이에 ThreadPool 이 사용되는 경우가 있다. 대표적으로 아래와 같다.

    • Task 또는 Taks<Result> 를 만들어 비동기 작업을 수행할 때, 기본적으로 Task 가 ThreadPool 의 Thread 를 실행시키도록 스케쥴링 된다.
    • 비동기 타이머도 ThreadPool 을 이용한다. ThreadPool 은 System.Threading.Timer 클래스로부터 콜백을 받아 실행한다. 또, System.Timers.Timer 클래스에서 이벤트를 받아 이벤트를 발생시키기도 한다.


ThreadPool 에서 알아두어야 할 사항

ThreadPool 이 Thread 를 재사용 하는 경우 Thread local storage 나 ThreadStaticAttribute 속성에 마킹된 필드에 데이터를 삭제하지 않는다. 따라서 Thread local storage 나 해당 속성을 참조하는 함수의 경우 이전에 사용되었던 값이 남아있을 수 있다. 그리고 ThreadPool 은 프로세스 당 하나 씩 존재하는데, .NET 4.0 부터 ThreadPool 의 기본 사이즈는 여러가지 요인에 의해서 달라질 수 있다. ( 어떤 환경에서는 최소 생성 쓰레드가 4개 이고, 어떤 환경에서는 8개 이다. )
























ThreadPool


It's in System.Threading namespace. It provides a pool of threads. Pool means some contents in some space that is big enough to see with one slight look ( typically rectangular shape ). If the content is water, then the pool becomes swimming pool, and if the inside stuff is a series of billiard balls, then it becomes a pool table. That's the general picture of pool.


Thus ThreadPool means the space where threads live inside. You can allocate some asynchronous I/O tasks or some specific jobs through ThreadPool and offload the work items to one of the threads in the thread pool.




The pros of ThreadPool

    • You don't have to create your own Thread which is computationally very expensive because there're a few threads that ThreadPool had created.
    • You can use ThreadPool API to allocate a delegate for ThreadPool to execute it later automatically. 
    • Not only ThreadPool offloads the delegate to a thread, it also manages the life cycle of threads.
    • Creating and deleting threads are on demand. It automatically creates one or deletes one when it thinks it's necessary.


The cons of ThreadPool

    • It may not be suitable for heavy weight, slow jobs. You may need a dedicated, your-own created thread for that.
    • If a task takes longer than a second, it's recommended to create your own thread.
    • You can't wait a task or cancel it unlike TPL ( Task Parallel Library )
    • You just can't reorder the jobs in the queue because it's FIFO.


ThreadPool example

Let's see the simple example of using ThreadPool.


Via ThreadPool.QueueUserWorkItem(LightweightThread), static void function has been passed into the queue as a delegate. Now the ThreadPool allocates the delegate to a thread and gets the thread started and then when the job is done, ThreadPool gets the thread ready again for accepting new, another requests. It's like renting a thread registered in ThreadPool when dequeueing an item from the queue in ThreadPool. 

Quiz

what if you delete the Thread.Sleep(1000) there?

=> The main thread of Main() will terminate before ThreadPool executes the static void method. Since ThreadPool uses a background thread, after the foreground thread has exited, the background thread is no longer able to survive.




What uses ThreadPool

Other than explicitly using the ThreadPool API, there're more things using ThreadPool. Typically, below.

    • When you create Task or Task<Result>Task for asynchronous jobs, basically the Task is scheduled to run a thread in ThreadPool.
    • Asynchronous timer also uses ThreadPool. ThreadPool executes a callback from System.Threading.Timer class and so does from System.Timers.Timer class.


Something you should know

When ThreadPool reuses a thread, it doesn't clear away the data in the thread local storage or ThreadStaticAttribute attribute. Thus if your method looks at the attribute or the storage, there might be some values left over that the previous job in the thread used. And the ThreadPool exists per a process, from .NET 4.0 the default size of ThreadPool can be vary from environment to environment. ( Some set 4 for minimum threads, others 8 for them )
































Comments