본문 바로가기
개발이야기/C#

[C#] BackgroundWorker를 이용한 다중 스레드 처리

by S코델리아2 2024. 7. 5.
728x90
반응형

C#으로 개발할 때 UI와 데이터 처리를 분리하지 않으면

데이터 처리를 하는 동안 UI가 멈추는 현상이 발생할 수 있다.

즉 데이터처리와 UI와 분리하여 실행하여야

UI의 응답성을 유지하면서 데이터처리를 할 수 있어

프로그램이 부드럽고 깔끔하게 실행된다.

이럴 때 백그라운드 워커(BackgroundWorker)를 사용하면 된다

백그라운드 워커(BackgroundWorker) 주요 기능

  1. 오랜 시간이 걸리는 데이터 처리 작업을 UI 스레드와 분리하여 실행하고자 할 때
  2. 모니터링 프로그램과 같이 작업의 진행 상황을 실시간으로 UI에 표시하고자 할 때

백그라운드 워커(BackgroundWorker) 예제

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace BackgroundWorkerExample
{
    public partial class MainForm : Form
    {
        private BackgroundWorker worker = new BackgroundWorker();

        public MainForm()
        {
            InitializeComponent();

            //진행률
            backgroundWorker1.WorkerReportsProgress = true;

            //취소여부
            backgroundWorker1.WorkerSupportsCancellation = true;

            //수행할 작업(데이터처리)
            backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);

            //진행률 UI 반영
            backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
            
            //백그라운드 작업 완료 되면 호출
            backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            if (!backgroundWorker1.IsBusy)
            {
                // 백그라운드 작업 시작
                backgroundWorker1.RunWorkerAsync();
            }
        }

        private void cancelButton_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy)
            {
                // 백그라운드 작업 취소 요청
                backgroundWorker1.CancelAsync();
            }
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            int total = 100; // 예시로 1부터 100까지의 합을 구한다고 가정

            for (int i = 1; i <= total; i++)
            {
                //작업자 취소여부
                if (worker.CancellationPending)
                {
                    //작업취소
                    e.Cancel = true;
                    break;
                }
                else
                {
                    // 작업 진행 상황을 보고
                    worker.ReportProgress((int)((float)i / total * 100));

                    // 장기 실행 작업 수행
                    System.Threading.Thread.Sleep(100); // 예시로 0.1초 대기
                }
            }

            // 결과 반환
            e.Result = total;
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // 진행률 업데이트
            progressBar.Value = e.ProgressPercentage;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                MessageBox.Show("작업이 취소되었습니다.");
            }
            else if (e.Error != null)
            {
                MessageBox.Show("에러가 발생하였습니다: " + e.Error.Message);
            }
            else
            {
                int result = (int)e.Result;
                MessageBox.Show("작업이 완료되었습니다. 결과는 " + result + " 입니다.");
            }
        }
    }
}

 

BackgroundWorker 클래스는 이벤트를 기반으로 하는 비동기 처리를 한다.

실제 데이터처리를 DoWork에서 진행하고

ProgressChanged 이벤트를 통한 진행률 보고,

RunWorkerCompleted 이벤트를 통한 작업 완료 후 UI 갱신 및 에러 처리 등

데이터 처리와 UI 처리를 분리하여 UI의 응답성을 높일 수 있다.

물론 상황에 따라서 Thread 나 Task를 사용하여 성능이 더 좋을 수가 있다.

상황에 따라 적절히 잘 사용해 보자!

 

728x90
반응형