Parallel 클래스를 활용한 멀티스레딩 프로그래밍

  1. Parallel.ForEach()의 활용

Parallel.ForEach() 메서드는 제네릭 컬렉션을 순회하는 데 사용됩니다. ASP.NET Core 웹 애플리케이션 프로젝트에서 이를 사용해 보겠습니다.

먼저, Member.cs라는 클래스를 생성하고 다음과 같이 코드를 작성합니다:

public class Member
{
    public int Id { get; set; }
    public string Name { get; set; }
}

그 다음, Index.cshtml.cs 파일의 IndexModel 클래스에 테스트 메서드 ParallelForEachDemo()를 추가합니다:

public void OnGet()
{
    ParallelForEachDemo();
}

public string ResultDisplay; // 페이지에서 값을 가져올 변수

public void ParallelForEachDemo()
{
    List<Member> memberList = new List<Member>
    {
        new Member{ Id=1, Name="김철수" },
        new Member{ Id=2, Name="박영희" },
        new Member{ Id=3, Name="이길동" },
        new Member{ Id=4, Name="최정민" },
        new Member{ Id=5, Name="홍길자" }
    };

    string allNames1 = string.Empty;
    Stopwatch timer1 = new Stopwatch();
    timer1.Start();
    foreach (Member member in memberList)
    {
        allNames1 += member.Name + ",";
        Thread.Sleep(10); // 시간 소요 작업을 시뮬레이션
    }
    timer1.Stop();

    string allNames2 = string.Empty;
    Stopwatch timer2 = new Stopwatch();
    timer2.Start();
    Parallel.ForEach(memberList, member => // 멀티스레드 순회
    {
        allNames2 += member.Name + ",";
        Thread.Sleep(10); // 시간 소요 작업을 시뮬레이션
    });
    timer2.Stop();

    ResultDisplay = string.Format("단일 스레드 순회 시간: {0}ms, 멀티스레드 순회 시간: {1}ms",
        timer1.ElapsedMilliseconds, timer2.ElapsedMilliseconds);
}

Index.cshtml.cs 파일에서 ResultDisplay 변수의 값을 출력하는 부분은 다음과 같습니다:

<div class="text-center">
    <h1 class="display-4">환영합니다</h1>
    <br />
    <p>@Model.ResultDisplay</p>
</div>

컴파일 후 실행하면, 결과는 단일 스레드보다 멀티스레드가 더 빠르게 처리됨을 확인할 수 있습니다.

  1. Parallel.Invoke()의 활용

다음으로, 여러 웹사이트에 동시에 접속하여 응답 문자열 길이를 측정하는 예제를 살펴보겠습니다. 이 역시 Index.cshtml.cs 파일의 IndexModel 클래스 내에서 구현합니다:

public void CountLength(string source, string url)
{
    long length = 0;

    HttpWebRequest request = WebRequest.CreateHttp(url); // 주어진 URL로 요청 생성
    HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // 응답 객체 획득
    length = response.ContentLength; // 응답 내용 길이 획득

    DisplayResult += "<tr><td>" + source + "</td><td>" + Thread.CurrentThread.ManagedThreadId + "</td>" +
                     "<td>" + url + "</td><td>" + length + "</td></tr>";
}

단일 스레드로 세 번의 함수 호출을 순차적으로 실행하는 코드는 다음과 같습니다:

public string SingleFetch()
{
    Stopwatch watch1 = new Stopwatch();
    watch1.Start();
    CountLength("single", "http://www.google.com");
    CountLength("single", "http://www.naver.com");
    CountLength("single", "http://www.daum.net");
    watch1.Stop();

    return watch1.ElapsedMilliseconds.ToString();
}

멀티스레드로 세 번의 함수 호출을 병렬로 실행하는 코드는 다음과 같습니다:

public string MultiFetch()
{
    Stopwatch watch2 = new Stopwatch();
    watch2.Start();
    Parallel.Invoke(
        () => CountLength("multi", "http://www.google.com"),
        () => CountLength("multi", "http://www.naver.com"),
        () => CountLength("multi", "http://www.daum.net")
    );
    watch2.Stop();

    return watch2.ElapsedMilliseconds.ToString();
}

OnGet() 메서드에서는 각각 단일 스레드와 멀티스레드 방법을 호출하며 결과를 표시하기 위한 코드도 포함되어 있습니다:

public string ResultDisplay;
public string DisplayResult;
public void OnGet()
{
    string timeSingle = SingleFetch(); // 단일 스레드 실행 시간
    string timeMulti = MultiFetch(); // 멀티스레드 실행 시간

    ResultDisplay = string.Format("단일 스레드 시간: {0}ms, 멀티스레드 시간: {1}ms", timeSingle, timeMulti);

    DisplayResult = "| 타입 | 스레드 ID | 웹사이트 | 응답 길이 |
|---|---|---|---|";
}

마지막으로, Index.cshtml 파일에서 결과를 표시하는 코드는 다음과 같습니다:

<div class="text-center">
    <h1 class="display-4">환영합니다</h1>
    <br />
    <p>@Model.ResultDisplay</p>
    <br />
    <p>@Html.Raw(Model.DisplayResult)</p>
</div>

이 코드를 컴파일하고 실행하면, 멀티스레드 방식이 단일 스레드 방식보다 빠른 것을 확인할 수 있습니다.

태그: ASP.NET Core Parallel.ForEach Parallel.Invoke 멀티스레딩

9월 14일 09:01에 게시됨