반응형
C# 스레드풀(Thread Pool) 개념
1. 스레드풀(Thread Pool)이란?
스레드풀은 미리 생성된 스레드의 집합으로, 여러 작업을 효율적으로 처리하기 위해 사용됩니다. 스레드풀은 스레드 생성과 관리를 자동으로 처리하여 시스템 자원을 효율적으로 사용하고, 개발자가 스레드를 직접 관리해야 하는 부담을 줄여줍니다.
2. 스레드풀의 주요 특징
- 자동 스레드 관리:
- 스레드풀은 작업량에 따라 스레드를 동적으로 추가하거나 재사용합니다.
- 불필요한 스레드 생성과 제거를 방지하여 성능을 최적화합니다.
- 제한된 스레드 개수:
- 스레드풀의 최대/최소 스레드 개수를 설정할 수 있습니다.
- 기본적으로 .NET 스레드풀은 각 논리적 CPU 코어당 스레드를 관리합니다.
- 작업 대기열(Task Queue):
- 스레드풀이 현재 실행 중인 작업보다 더 많은 작업 요청을 받을 경우, 작업이 대기열에 추가됩니다.
- 대기열에 있는 작업은 스레드가 사용 가능해질 때 처리됩니다.
- 비동기 프로그래밍과 통합:
- Task 및 async/await와 함께 사용되며, 이를 통해 스레드풀 작업을 비동기적으로 실행할 수 있습니다.
3. 스레드풀을 사용하는 이유
- 효율성:
- 스레드를 직접 생성하는 대신, 재사용 가능한 스레드풀을 사용하면 성능이 개선됩니다.
- 자원 절약:
- 불필요한 스레드 생성을 방지하고, 시스템 자원(CPU, 메모리 등)을 효율적으로 사용합니다.
- 간소화:
- 개발자는 스레드 생성과 관리에 신경 쓰지 않고, 스레드풀을 통해 작업을 쉽게 처리할 수 있습니다.
4. 주요 클래스 및 메서드
- ThreadPool 클래스:
- QueueUserWorkItem: 작업을 스레드풀에 추가합니다.
- SetMinThreads: 스레드풀의 최소 스레드 개수를 설정합니다.
- SetMaxThreads: 스레드풀의 최대 스레드 개수를 설정합니다.
- Task 클래스:
- Task.Run: 스레드풀에서 작업을 실행합니다. 비동기 프로그래밍과 통합됩니다.
5. 예제 코드와 설명
5.1 ThreadPool 사용 예제
using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
// 스레드풀에 작업 추가
for (int i = 1; i <= 5; i++)
{
int taskNumber = i; // 로컬 변수로 캡처
ThreadPool.QueueUserWorkItem(PerformTask, taskNumber);
}
// 메인 스레드가 종료되지 않도록 대기
Console.WriteLine("Main thread waiting...");
Thread.Sleep(3000); // 대기 시간
}
static void PerformTask(object taskNumber)
{
Console.WriteLine($"Task {taskNumber} is starting on thread {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000); // 작업 시뮬레이션
Console.WriteLine($"Task {taskNumber} is completed on thread {Thread.CurrentThread.ManagedThreadId}");
}
}
결과 설명
- ThreadPool.QueueUserWorkItem:
- 작업을 스레드풀에 추가합니다.
- 스레드풀이 가능한 스레드에서 PerformTask를 실행합니다.
- PerformTask 메서드:
- 각 작업은 고유한 스레드 ID를 통해 실행됩니다.
- 작업이 시작될 때와 완료될 때 로그를 출력합니다.
- 결과 예시 출력:
Task 1 is starting on thread 4
Task 2 is starting on thread 5
Task 3 is starting on thread 6
Task 4 is starting on thread 7
Task 5 is starting on thread 8
Task 1 is completed on thread 4
Task 2 is completed on thread 5
Task 3 is completed on thread 6
Task 4 is completed on thread 7
Task 5 is completed on thread 8
Main thread waiting...
5.2 Task.Run 사용 예제 (비동기 프로그래밍과 통합)
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// 비동기 작업 실행
Task[] tasks = new Task[5];
for (int i = 0; i < 5; i++)
{
int taskNumber = i + 1; // 로컬 변수로 캡처
tasks[i] = Task.Run(() => PerformTask(taskNumber));
}
// 모든 작업이 완료될 때까지 대기
await Task.WhenAll(tasks);
Console.WriteLine("All tasks completed!");
}
static async Task PerformTask(int taskNumber)
{
Console.WriteLine($"Task {taskNumber} is starting on thread {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(1000); // 비동기 대기
Console.WriteLine($"Task {taskNumber} is completed on thread {Thread.CurrentThread.ManagedThreadId}");
}
}
결과 설명
- Task.Run:
- 스레드풀에서 작업을 실행합니다.
- 작업이 비동기로 실행되며, 다른 작업과 병렬로 처리됩니다.
- Task.WhenAll:
- 모든 작업이 완료될 때까지 대기합니다.
- 결과 예시 출력:
Task 1 is starting on thread 4
Task 2 is starting on thread 5
Task 3 is starting on thread 6
Task 4 is starting on thread 7
Task 5 is starting on thread 8
Task 1 is completed on thread 4
Task 2 is completed on thread 5
Task 3 is completed on thread 6
Task 4 is completed on thread 7
Task 5 is completed on thread 8
All tasks completed!
6. 스레드풀의 장점과 한계
장점:
- 스레드 관리 자동화: 스레드 생성 및 소멸 관리 불필요.
- 자원 효율성: 스레드 재사용으로 자원 낭비 최소화.
- 비동기 프로그래밍과 연계 가능: Task와 함께 사용 시 매우 편리.
한계:
- 스레드 수 제한: 스레드풀이 한 번에 처리할 수 있는 작업 수는 제한적.
- 복잡한 작업 시 제어 부족: 특정 스레드에 우선순위를 두는 작업 등은 직접 구현해야 함.
7. 요약
- **스레드풀(Thread Pool)**은 작업의 효율적 처리를 위해 미리 생성된 스레드 집합을 관리합니다.
- ThreadPool.QueueUserWorkItem으로 작업을 스레드풀에 추가할 수 있고, 비동기 작업에는 Task.Run을 사용합니다.
- 스레드풀은 스레드 생성/관리를 자동화하여 성능과 자원 효율성을 높입니다.
- 간단한 동시 작업이나 비동기 프로그래밍에서 매우 유용합니다.
궁금한 점이 있거나 더 깊이 알고 싶은 내용이 있다면 언제든 질문해주세요! 😊
반응형
'C# > 쓰레드' 카테고리의 다른 글
C# 태스크(Task)와 비동기 프로그래밍: 생성, 연속 작업, 부모-자식 관계 이해 (1) | 2025.01.20 |
---|---|
C# Task 기본 동작과 스레드 실행 시나리오 이해 (12) | 2025.01.17 |
C# TPL: 태스크 생성 방식과 실행 흐름 완벽 이해 (1) | 2025.01.17 |
C# `Thread`와 `ThreadPool`의 차이점 및 델리게이트 비동기 호출 이해 (17) | 2025.01.16 |
C# SemaphoreSlim: 멀티스레드 리소스 접근 제어 예제와 설명 (2) | 2025.01.16 |
C# 스레드 제어: Semaphore와 SemaphoreSlim의 차이와 사용법 (2) | 2025.01.16 |
C# Mutex로 프로세스 단일 인스턴스 제어하기 (1) | 2025.01.16 |
원자적 작업(Atomic Operation): 동시성 문제 해결의 핵심 개념 (2) | 2025.01.16 |