C# and .NET Core 멀티스레딩(multithreading)

멀티스레딩은 프로그램을 여러 스레드로 나누는 방식을 의미하며, 각 스레드는 독립적으로 동시에 실행될 수 있습니다. 이로 인해 특히 I/O 또는 네트워크 통신과 같은 작업의 경우 성능과 응답성이 향상될 수 있습니다. C# 및 .NET Core에서는 System.Threading 네임스페이스를 사용하여 스레드를 만들고 관리할 수 있습니다.

다음은 Thread 클래스를 사용하여 C#에서 새 스레드를 만드는 예입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using System;
using System.Threading;

class Program {
static void Main(string[] args) {
Thread thread = new Thread(new ThreadStart(Worker));
thread.Start();

Console.WriteLine("Main thread is running.");
Console.ReadLine();
}

static void Worker() {
Console.WriteLine("Worker thread is running.");
}
}

이 예제에서는 Thread 클래스를 사용하여 새 스레드를 만들고 Worker 메서드에 대리자를 전달합니다. 그런 다음 Start 메서드를 사용하여 스레드를 시작하고 Worker 메서드는 Main 메서드와 동시에 실행됩니다. 이 프로그램을 실행하면 다음과 같은 출력이 표시됩니다.

1
2
Main thread is running.
Worker thread is running.

.NET Core는 다중 스레드 코드 작업을 위한 다양한 클래스와 구문도 제공합니다. 그중 하나는 병렬 작업을 실행하는 간단한 방법을 제공하는 TPL(작업 병렬 라이브러리)입니다. 다음은 TPL을 사용하여 병렬 루프를 실행하는 예입니다.

1
2
3
4
5
6
7
8
9
10
11
using System;
using System.Threading.Tasks;

class Program {
static void Main(string[] args) {
Parallel.For(0, 10, i => {
Console.WriteLine("Processing item {0} on thread {1}", i, Task.CurrentId);
});
Console.ReadLine();
}
}

이 예제에서는 Parallel.For 메서드를 사용하여 루프를 병렬로 실행하며 각 반복은 별도의 스레드에서 실행됩니다. Task.CurrentId 속성을 사용하여 현재 반복을 실행하는 스레드의 ID를 표시합니다. 이 프로그램을 실행하면 다음과 유사한 출력이 표시됩니다.

1
2
3
4
5
6
7
8
9
10
Processing item 0 on thread 4
Processing item 1 on thread 6
Processing item 2 on thread 5
Processing item 3 on thread 7
Processing item 4 on thread 8
Processing item 5 on thread 4
Processing item 6 on thread 6
Processing item 7 on thread 5
Processing item 8 on thread 7
Processing item 9 on thread 8

이는 C# 및 .NET Core가 다중 스레드 프로그래밍을 지원하는 다양한 방식 중 작은 예일뿐입니다.

이미지 처리 또는 비디오 트랜스코딩과 같이 CPU를 많이 사용하는 장기 실행 작업을 수행해야 하는 웹 API가 있는 시나리오를 생각해 보세요. 메인 스레드에서 이 작업을 수행하면 다른 수신 요청이 차단되고 API의 응답 속도가 느려집니다. 이 문제를 해결하려면 멀티스레딩을 사용하여 별도의 스레드에서 작업을 수행하고 기본 스레드가 들어오는 요청을 처리할 수 있도록 남겨둘 수 있습니다.

다음은 작업 병렬 라이브러리를 사용하여 .NET Core 웹 API에서 이를 달성할 수 있는 방법의 예입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("[controller]")]
public class ImageController : ControllerBase {
[HttpPost]
public async Task<IActionResult> ProcessImage() {
// Parse incoming request and extract image data
// ...

// Start processing on a separate thread
Task<byte[]> task = Task.Run(() => {
// Perform CPU-intensive image processing
// ...
return processedImageData;
});

// Return a response immediately, while the image is being processed
return await task;
}
}

이 예에서는 이미지 데이터가 포함된 수신 HTTP POST 요청을 처리하는 웹 API 컨트롤러에 ProcessImage 작업 메서드를 정의합니다. 그런 다음 별도의 스레드에서 지정된 대리자를 실행하는 새 Task을 만드는 Task.Run 메서드를 사용하여 별도의 스레드에서 이미지 처리를 시작합니다. 처리가 완료될 때까지 기다리고 처리된 이미지 데이터를 반환하기 위해 wait 키워드를 사용하여 Task를 응답으로 즉시 반환합니다.

이 방식을 사용하면 웹 API의 기본 스레드가 들어오는 요청에 계속 응답하는 동시에 이미지 처리가 별도의 스레드에서 수행됩니다. 이는 API의 전반적인 성능과 확장성을 향상시키는 데 도움이 될 수 있습니다.

첫 번째 예에서는 System.Threading 네임스페이스를 사용하여 C# 및 .NET Core에서 스레드를 만들고 관리하는 방법을 살펴보았습니다. 우리는 새로운 스레드를 생성하고 해당 스레드에서 별도의 메서드를 실행하는 간단한 프로그램을 만들었습니다. 이를 통해 두 개의 별도 코드 조각을 동시에 실행할 수 있어 특정 시나리오에서 성능과 응답성을 향상시킬 수 있습니다.

두 번째 예에서는 .NET Core 웹 API에서 고급 멀티스레딩 기술을 사용하는 방법을 살펴보았습니다. 우리는 Task Parallel 라이브러리를 사용하여 별도의 스레드에서 long-running, CPU-intensive 작업을 시작하는 동시에 기본 스레드는 들어오는 요청을 처리할 수 있도록 자유롭게 유지했습니다. 이는 특히 long-running 작업으로 인해 들어오는 요청이 차단될 수 있는 시나리오에서 API의 전반적인 성능과 확장성을 개선하는 데 도움이 될 수 있습니다.

전반적으로 멀티스레딩은 C# 및 .NET Core 애플리케이션의 성능과 응답성을 향상시키는 강력한 도구가 될 수 있습니다. 그러나 이를 현명하게 사용하고 복잡성 증가, 잠재적 경합 조건 또는 동기화 문제, 리소스 사용량 증가와 같은 잠재적인 절충안을 이해하는 것이 중요합니다. 특정 시나리오에 적합한 스레딩 구성 및 기술을 사용하면 이러한 잠재적 위험을 피하면서 멀티스레딩의 이점을 활용할 수 있습니다.

Share