C# Task의 TaskCreationOptions별 실행 비교와
ThreadPool의 관계
(SetMinThreads SetMaxThreads)
http://msdn.microsoft.com/ko-kr/library/system.threading.threadpool.getmaxthreads.aspx
이번 포스트에서는 "Thread를 컨트롤"의 라디오 버튼을 이용해서 SetMinThreads와 SetMaxThreads를 통해 제한된 상황을 만들어서 컨트롤 하는 시나리오를 검토해 보도록 하겠습니다. 지난 시간에 포스트 할때 배포 되었던 소스에서 약간더 수정한 소스를 다시 올려 드리며 추가된 화면 컨트롤에 대한 설명을 더 진행하도록 하겠다.
[그림1] 새로 추가된 테스트 화면
"그림1"에서와 같이 추가된 컨트롤에 대한 설명을 "표1"에 설명 한다.
컨트롤 명 |
설명 |
Available Thread Count |
ThreadPool에서 사용 가능한 쓰레드 수 |
Available IOC Thread Count |
ThreadPool에서 I/O 관련 사용 가능한 쓰레드 수 |
[표1] 추가된 컨트롤에 대한 설명
추가된 기능은 실시간으로 ThreadPool에서 사용가능한 쓰레드 수를 화면에 보여주도록 하여 Thread 컨트롤에서 어떻게 동작하는지 보다 정확히 알 수 있도록 하였다.
이제 "시나리오2"처럼 실행을 해보자.
시나리오2
1. "Thread를 컨트롤" 라디오 버튼을 클릭 2. 기본 세팅되어 있는 Min Worker : 4, Max Worker : 4를 확인 한다. 3. "Set" 버튼을 클릭 4. "Async Processing" 버튼 클릭 5. 동시 실행 갯수 확인 6. MaxWorker을 6으로 수정 7. "Clear" 버튼 클릭 8. "Set" 버튼 클릭 9. "Async Processing"버튼 클릭 10. 동시 실행 갯수 확인 |
이제 시나리오 2와 같이 실행하면 "Thread"컨트롤 라디오 버튼을 클릭하면 임의의 값으로 ThreadPool을 설정할 수 있으며 설정된 정보와 같이 Task 비 동기 실행이 되는 것을 확인 할 수 있다.
[그림1] MaxWorker을 4로 세팅하고 수행하는 화면
[그림2] MaxWorker을 6로 세팅하고 수행하는 화면
"그림1"과 "그림2"에서 확인된 것과 같이 MaxWorker로 설정된 값을 기준으로 초기 동시 실행 갯수가 제한되는 것을 확인할 수 있다. 이제 대략적인 프로그램에 대한 설명을 마친다. 이제 전체적인 개념과 프로그램 화면에 대한 사용 방법 및 개념에 대해서 어느정도 이해를 할 수 있을 정도일 것으로 예상하고 이제 소스 코드에 대해 알아 보도록 하자. 다운받을 수 있게 소스 코드를 올려 놓을 것이니 포스트에서는 핵심 코드에 대해 부가적인 설명이 필요한 부분에 대해서만 진행 하겠다. 다시 한번 더 부탁드리자면 직접 디버깅을 통해 실행 하면서 체험해 보는것이 가장 좋고 소스에 같이 주석처리된 코멘트를 잘 읽어 간다면 보다 쉽게 체득할 수 있을거라 장담한다. 이제 코드를 살펴 보도록 하자.
다운받기
TaskTest_Next.zip
<RadioButton VerticalAlignment="Center" x:Name="rdoCustomerThreadControl" Content="Thread를 컨트롤" HorizontalAlignment="Center" Margin="5, 0, 0, 0"></RadioButton>
<StackPanel Orientation="Horizontal" Margin="20, 0, 0, 0" IsEnabled="{Binding ElementName=rdoCustomerThreadControl, Path=IsChecked, Mode=TwoWay}">
[코드1] 메인 화면의 Xaml중에서 Binding을 통해 값 연결
"코드1"에서는 IsEnabled="{Binding ...}을 통해 radCustomerThreadControl의 값이 실시간으로 변홤에 따라서 IsEnabled의 값이 변경이 되도록 Xaml단에서 연결 시켜 놓는 작업이다. 이 작업은 UI단에서의 작업이므로 전체 로직에서 차지하는 비중을 차지 하지는 않는다. 다만 Xaml을 하는 장점을 한번 보여드리고자 하였다.
// 일정 간격마다 ThreadPool을 가져와서 화면에 보여준다.
Task.Factory.StartNew(() => {
while (true)
{
//Min thread work
int minWorker, minIOC;
ThreadPool.GetMinThreads(out minWorker, out minIOC);
// 가져온 값으로 화면에 보여준다.
tbMinThreadCount.Dispatcher.BeginInvoke(new Action(() => { tbMinThreadCount.Text = minWorker.ToString(); }), null);
//Max thread work
int maxWorker, maxIOC;
ThreadPool.GetMaxThreads(out maxWorker, out maxIOC);
// 가져온 값으로 화면에 보여준다.
tbMaxThreadCount.Dispatcher.BeginInvoke(new Action(() => { tbMaxThreadCount.Text = maxWorker.ToString(); }), null);
// 특정 시간에 스레드 풀에 있는 실제 스레드 수를 확인
int availableWorkThreads, availableCompletionPortThreads;
ThreadPool.GetAvailableThreads(out availableWorkThreads, out availableCompletionPortThreads);
tbAvailableThreadCount.Dispatcher.BeginInvoke(new Action(() => {
tbAvailableThreadCount.Text = availableWorkThreads.ToString();
tbAvailableCompletionThreadCount.Text = availableCompletionPortThreads.ToString();
}));
Thread.Sleep(1000);
}
});
[코드2] ThreadPool의 상태를 화면에 적용 하는 코드
"코드2"는 ThreadPool의 상태를 가져와서 텍스트 박스에 할당하는 작업을 비 동기, 주기적으로 갱신하도록 하였다. 이 작업은 실행되는 풀의 내부 상태를 바로 알 수 있도록 하기 위한것이고 동시 실행갯수에 따라서 변경되는 것을 확인할 수 있다.
// 스레드 작성 및 소멸을 관리하기 위한 알고리즘으로 전환하기 전에 새 요청에 따라 스레드 풀이 생성하는 스레드의 최소 수를 설정합니다.
// minWorker : 스레드 풀에서 필요할 때 만드는 작업자 I/O 스레드의 최소 개수입니다.
// minIOC : 스레드 풀에서 필요할 때 만드는 비동기 I/O 스레드의 최소 개수입니다. File.BeginWrite(,,,) 와 같이 파일 관련 비동기 함수를 실해할 때 MinIOC를 쓰레드에서 실행한다. // http://msdn.microsoft.com/ko-kr/library/system.threading.threadpool.getmaxthreads.aspx 확인 가능
ThreadPool.SetMinThreads(minWorker, minIOC);
// 동시에 활성 상태가 될 수 있는 스레드 풀에 대한 요청 수를 설정합니다. 해당 수를 넘는 모든 요청은 스레드 풀 스레드가 사용 가능해질 때까지 큐에 대기 상태로 남아 있습니다.
// maxWorker : 스레드 풀에 있는 최대 작업자 스레드 수입니다.
// minIOC : 스레드 풀에서 필요할 때 만드는 비동기 I/O 스레드의 최소 개수입니다. File.BeginWrite(,,,) 와 같이 파일 관련 비동기 함수를 실해할 때 MinIOC를 쓰레드에서 실행한다. // http://msdn.microsoft.com/ko-kr/library/system.threading.threadpool.getmaxthreads.aspx 확인 가능
ThreadPool.SetMaxThreads(maxWorker, maxIOC);
[코드3] ThreadPool에 Thread의 활동 제한을 설정 하는 코드
"코드3"은 자동으로 변경되는 ThreadPool의 활성화 작업을 제한하는 코드로서 최저와 최고치를 설정하여 활성화 되는 쓰레드의 갯수를 제한한다. 이 작업은 "Thread를 컨트롤" 버튼을 눌러 활성화 시켰을 때에만 수행 하도록 되었다.
Task.Factory.StartNew(() =>
{
for (int i = 1; i <= count; i++)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
var stackPanel = GetProgressBar();
// 제공된 컨트롤을 리스트 객채에 넣는다.
lstTaskResult.Items.Add(stackPanel);
}));
}
});
[코드4] 진행바를 ListItem 객체에 추가하는 코드
GetProgressBar()에서 프로그래밍 적으로 프로그래스바를 화면에 보일 수 있도록 구성한 다음 진행바가 수행하는 작업을 연결 시켜 비 동기로 수행이 되도록 세팅된 StackPanel을 받아 ListItem 객체에 자식 컨트롤로 추가하는 코드다.
// Processing 버튼을 눌렀을 때 비 동기 Task가 활성화 되도록 처리 함.
Task.Factory.StartNew(() => {
// Task를 활성화 시킴
tasks.ForEach(task => task.Start());
// 모두 완료가 될때까지 대기
Task.WaitAll(tasks.ToArray());
// 모든 Task가 수행을 마쳐 더 이상 관리가 필요 없어져서 관리에서 제거
tasks.Clear();
});
[코드5] 진행바에 연결된 Task를 활성화 시키는 코드
ForeEach의 Linq 구문을 통해 쉽게 수행이 되도록 하였으며 Task.WaitAll로 모두 완료가 될때가지 대기하도록 하였다. 완료가 되면 더 이상 사용하지 않는 Task이므로 Clear을 통해 모두 초기화 시켜주는 작업을 하였다.
이번 포스트는 소스코드를 포함하여 포스팅되었으며 전체 소스 설명 보다는 중요한 부분에 대해서 간략하게 설명하게 되었다. 자세한 설명은 소스를 받아 살펴 볼 수 있을 것이다.
이 프로그램을 사용하여 Task의 비 동기 수행에 대한 특성을 좀더 쉽게 알 수 있었으면 하는 바램으로 이 글을 올리게 되었다.
Tip ! 아래와 같이 Framework에 따라 최대 허용 쓰레드 수가 다르다. ThreadPool.SetMaxThread를 통해 세팅할 수 있다.
최대 쓰레드 수 |
Platform 환경 |
1023 |
32비트 .Net Framework 4 |
32768 |
64비트 .Net Framework 4 |
250 per Core |
.Net Framework 3.5 |
25 per Core |
.Net Framework 2 |
|
소스 코드 자체에 주석과 직관적인 코딩으로 충분히 파악이 가능할 것으로 예상하므로 별도의 설명을 생략하도록 하겠습니다. 포스트의 내용이 장황한 설명 보다는 주석과 소스코드 자체 만으로도 이해할 수 있도록 하기 위해 노력하였습니다.. 실제 개발에서도 필요한 소스는 단순히 Copy & Paste 만으로도 사용할 수 있습니다. 그리고 주석을 이용해 nDoc이나 별도의 자동 Document 제작 유틸로 API 문서를 만드는 데에도 도움이 되었으면 한다. ※ DOC에 대한 프로그램 정보 Util link ing™
|