분류 전체보기 (328)
.NET (111)
S/W tip (35)
etc (63)
DB (34)
HOT item~! (48)
Disign pettens (4)
UX (6)
나의 S/W (2)
개발관련 이슈 (16)
Diary (1)
웹플러스 (1)
calendar
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
tags
archive
link
ColorSwitch 00 01 02


출처 : http://cafe.naver.com/winform.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=103


 

주     제 BindingNavigator  

 
 작 성 자 : 박종명 (mkex)   


 작 성 일 : 2008년 02월 13일(수)  

  
 수 정 일 : 2008년 02월 13일(수) 

 

이번 포스트에서는 비동기 작업을 지원하는 BackgroundWorker 컴포넌트에 대해 알아 보겠습니다.

 

참고로 구성요소로 번역되는 컴포넌트는 컨트롤과는 달리 UI 를 가지고 있지 않습니다.

아래처럼 Visual Studio 의 도구상자를 통해 폼에 이 컴포넌트를 올리면 폼에 특별한 UI 는 나타나지 않은 채

하위 컴포넌트 목록 창에만 표시됩니다.

 

뭐.. 중요한 내용은 아니었구요..

 

비동기 작업이란 수행 시간이 오래 걸리는 작업을 백그라운드 상에서 별도로 처리한게 하는 방법입니다.

즉 메인 쓰레드와 분리된 쓰레드에서 작업을 수행하도록 하여 응용프로그램의 블럭을 방지하고 지연을

최소화하는 프로그래밍 방식입니다.

 

MSDN에서는 수행시간이 오래 걸리는 작업을 다음처럼 예시하고 있습니다.

  • 이미지 다운로드

  • 웹 서비스 호출

  • 파일 다운로드 및 업로드(피어-투-피어 응용 프로그램에 대한 다운로드 및 업로드 포함)

  • 복잡한 로컬 계산

  • 데이터베이스 트랜잭션

  • 로컬 디스크 액세스(메모리 액세스에 비해 상대적으로 속도가 느림)

     

    그리고 MSDN의 설명 한 마디를 보시죠..

    "BackgroundWorker 구성 요소를 사용하면 응용 프로그램의 주 UI 스레드와 다른 스레드에서 시간이 많이 소모되는

    작업을 백그라운드"에서 비동기적으로 실행할 수 있습니다"

     

    BackgroundWorker 컴포넌트는 닷넷 2.0 부터 새로이 추가된 컴포넌트 입니다.

    물론 이전 버전에서도 사용할 수 있었지만 닷넷 프레임워크에 포함된 형태는 아니었었습니다.

     

    BackgroundWorker 를 사용하기 전에는 이러한 비동기 작업을 처리하기 위해서 수동으로 작업자 쓰레드(Worker Thread)를

    직접 생성해서 주 쓰레드(Main Thread) 와 분리하여 작업을 처리하는 코드를 직접 작성했어야 했으며,

    작업 진행상황이나 작업 취소와 같은 일련의 작업을 개발자가 직접 해 주어야 했습니다.

    쓰레드에 관해서는 다음의 사이트의 글들을 참고 하시기 바랍니다.

     

    Process & Thread 개요

    Mulit Thread Programming

    ThreadState (Thread 상태)

    공급자/소비자 문제로 알아보는 동기화 문제

    [동기화] Monitor 클래스

    [동기화] Interlocked 클래스 와 lock 문

    [동기화] Mutex 클래스

    [동기화] Event

     

    이렇듯 멀티 쓰레드 프로그래밍을 작성할 때는 다양한 이슈가 있습니다.

    쓰레드 자체에 대한 자세한 내용은 위의 링크 및 기타 다른 자료로 학습을 하시면 되겠습니다.

    이번 글에서는 BackgroundWorker 컴포넌트의 사용방법에 대해서 다루겠습니다.

     

    * BackgroundWorker 의 이벤트

    이 컴포넌트를 사용하여 비동기 작업을 하고하 할 경우 알아야 이벤트에 대해서 알아 보겠습니다.

    BackgroundWorker 컴포넌트에는 3개의 이벤트가 있습니다.

     

    1) DoWork

        백그라운드 작업의 실제 실행을 처리하는 이벤트 입니다.

        단 이 이벤트는 자동으로 발생하지 않고 BackgroundWorker 의 RunWorkerAsync 메서드가 호출될 때 발생하게 됩니다.

        즉 개발자가 비동기 작업을 위해 RunWorkerAsync 메서드를 호출하면 자동으로 DoWork 이벤트가 발생하게 됩니다.

        RunWorkerAsync -> DoWork

     

    2) ProgressChanged

        백그라운드 작업의 진행률을 처리하기 위한 이벤트 입니다.

        이 이벤트 역시 개발자가 수종으로 발생 시켜줘야 하는데,

        BckgroundWorker 의 ReportProgress 메서드를 명시적으로 호출하여 이벤트를 발생시킬 수 있습니다.

        또한 연관된 속성으로는 WorkerReportProgress 로써 이 속성이 참(true) 로 설정되어 있어야 됩니다.

        ReportProgress -> ProgressChanged

     

    3) RunWorkerCompleted

        백그라운드 작업의 완료, 중도 취소, 예외가 생겼을 때 발생하는 이벤트 입니다.

        연관된 속성으로는 WorkerSupportsCancellation 로써 이 속성이 참(true) 로 설정되어 있어야 합니다.

        이 이벤트의 매개변수인 RunWorkerCompletedEventArgs 객체를 통해 작업이 중도에 취소되었는지, 예외가 발생했는지

        를 알 수 있습니다.

     

    이상 3가지 이벤트를 사용하여 손 쉽게 백그라운드 작업을 구현하실 수 있게 됩니다.

       

     

    * Demo

    일단 다음과 같이 오래 걸리는 작업을 수행하는 메서드(DelayMethod)를 작성하도록 합니다.

    현재 이 글에서는 이 작업이 무엇을 하는지가 중요한게 아니라 오래 걸리는 작업이 중요한 포인터이기 때문에

    실제로 오래걸릴만한 작업이 아닌 의도적으로 중간에 Sleep 를 걸어 두도록 하겠습니다.

     

    다음의 코드가 작업이 오래 걸리는 역할을 하는 메서드 정의입니다.

    매개변수로 최대값을 받아서 순차적으로 더해 갑니다. 그리고 최종 더한 값을 반환하도록 합니다.

    메서드의 지연처리를 위해 중간에 Thread.Sleep 으로 수행을 잠시 멈춥니다.

    (실제로 이런 코드는 있을 수는 없겠죠.. 하지만 테스트를 위해 아래처럼 작성하도록 합니다)

     private Int64 DelayMethod(int maxNumber)
     {
          Int64 result = 0;
          for (int i = 1; i <= maxNumber; i++)
          {
              result += i;
              System.Threading.Thread.Sleep(100);

          }

          return result;
     }

     

     

    1. 비동기로 처리 하지 않을 경우

    위 메서드를 백그라운드에서 처리하지 않고 동기방식으로 처리하도록 해 보겠습니다.

    폼에 버턴을 하나 두고 버턴을 클릭하면 위 메서드가 수행되고 끝나면 결과값을 Label 에 기록하는 간단한 샘플입니다.

    버턴이 클릭 되었을 때 다음처럼 메서드를 호출합니다.

     

    Int64 result =  DelayMethod(100);
    this.lblResult.Text = result.ToString();

     

    최대값을 100 을 주었고 중간중간에 100밀리 세컨드 만큼 수행을 멈추므로 이 작업은 시간이 조금 걸리는 작업이 됩니다.

    직접 실행을 해 보면 버턴을 클릭하고 난 후 부터 작업이 완료될 때 까지 폼이 멈춰버리고 다른 어떠한 작업도 할 수 없게 됩니다.

    또한 이 폼을 다시 보이게 하려면 다음처럼 하얀색 빈 바탕 화면처럼 나오게 됩니다.

     

    = 원래 폼 모양 =

       

     

    = 수행 도중 창을 내렸다가 다시 올렸을 경우의 모양 =

     

    시간이 오래 걸리는 작업을 동기로 구현한다면 이러한 문제가 발생합니다.

    즉 UI 쓰레드에서 직접 메서드를 수행하기 때문에 다른 곳에서는 제어권을 받을 수 가 없게 되는 것입니다.

     

     

    2. BackgroundWorker 를 이용해 비동기로 처리하기.

     

    이제 위 메서드를 비 동기로 처리 해 보겠습니다.

    우선 폼의 모양을 아래처럼 조금 다듬습니다.

     

    최대값을 사용자로 부터 입력 받기 위한 NumericUpDown 컨트롤과 작업의 시작,취소 버턴

    그리고 작업 진행률을 보기 위한 ProgressBar , 결과값 출력을 위한 Lable 컨트롤을 적절히 배치 하였습니다.

    이 샘플은 msdn 의 BackgroundWorker 샘플 중 피보나치 수열을 계산하는 샘플을 조금 변형한 것입니다.

     

     

    ① 비 동기 작업의 진행률과 취소를 지원하기 위해 두개의 속성을 설정합니다.

        (이 코드에서는 Form_Load 이벤트에서 작성합니다. 디자인 타임에 속성 창을 통해서 하셔도 됩니다)

       

     //최대값 저장을 위한 멤버 변수

     int maxNumber = 10; 

     

     //폼 로드 이벤트

     private void Form1_Load(object sender, EventArgs e)
     {
          //작업 진행률을 보고할 수 있도록 설정한다.
          this.backgroundWorker1.WorkerReportsProgress = true;
          //작업을 취소할 수 있도록 설정한다.
          this.backgroundWorker1.WorkerSupportsCancellation = true;
     }

     

    ② 다음으로 '작업 시작' 버턴을 클릭했을 때 다음 처럼 비동기 작업을 시작하도록 합니다.

     private void startAsyncButton_Click(object sender, EventArgs e)
     {

          //시작된 이후에 필요하지 않은 컨트롤은 사용 불가 처리 한다.

          this.numericUpDown1.Enabled = false;
          this.lblResult.Text = String.Empty;                                  
          this.startAsyncButton.Enabled = false;           
          this.cancelAsyncButton.Enabled = true;

     

          // 최대값 얻기
          int maxNumber = (int) numericUpDown1.Value;

     

          // 진행률 퍼센트 계산을 위한 변수 초기화
          highestPercentageReached = 0;

     

          //백그라운드 작업을 시작한다.이 메서드 호출은 DoWork 이벤트를 발생시킨다

          //이때 매개변수로 최대값을 넘겨 준다
          backgroundWorker1.RunWorkerAsync(maxNumber);
     }

     

     

    ③ 이제 본격적으로 BackgroundWorker 컴포넌트의 이벤트를 작성합니다.

     

    = DoWork 이벤트 =

     private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
     {           
          BackgroundWorker worker = sender as BackgroundWorker;
               
          //실제로 백그라운드에서 돌아갈 메서드를 호출한다 

          //이때 앞서 RunWorkerAsync 메서드 호출 시 전달한 매개변수를 e.Argument 로 다시 넘긴다.

          //그리고 비동기 작업의 결과 값을 EventArgument 의 Result 에 저장한다.
          e.Result = this.DelayMethod((int)e.Argument, worker, e);

     }

     

    = ProgressChanged 이벤트 =

     //BackgroundWorker 의 ReportProgress가 호출될때 발생한다. 비동기 작업 진행률을 보고 받는다
     private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
     {

          //ProgressBar 에 진행률을 표시한다
          this.progressBar1.Value = e.ProgressPercentage;
     }

     

    = RunWorkerCompleted 이벤트 =

     //백그라운드 작업이 완료되거나 취소되거나 예외를 발생시켰을 때 발생합니다
     private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
     {            
          //작업에 오류가 발생하면 메세지를 띄운다
           if (e.Error != null)
          {
              MessageBox.Show(e.Error.Message);
          }
          //작업이 취소되었으면 취소되었다는 메세지를 보여준다
          else if (e.Cancelled)
          {                
              lblResult.Text = "작업이 취소되었습니다";
          }
          //작업이 완료되면 결과값을 보여준다
          else
          {
              //결과값 출력
              lblResult.Text = e.Result.ToString();
          }
               
          //기타 컨트롤 사용가능케 설정
          this.numericUpDown1.Enabled = true;            
          startAsyncButton.Enabled = true;           
          cancelAsyncButton.Enabled = false;
     }

     

    ④ 취소 버턴 클릭 이벤트를 작성합니다

     private void cancelAsyncButton_Click(object sender, EventArgs e)
     {
          //비동기 작업을 취소를 요청한다.

          //이 메서드 호출로 BackgroundWorker 의 CancellationPending 속성이 true로 설정한다
          this.backgroundWorker1.CancelAsync();

          //취소 버턴 비활성화
          cancelAsyncButton.Enabled = false;
     }

     

    ⑤ 비동기로 수행될 메서드

    실제 시간이 오래 걸리는 작업을 하는 메서드 정의 입니다.

    기존 비지니스 처리 이외에 BackgroundWorker 의 작업 취소 감지 및 진행률 보고 로직이 포함되어야 합니다

     private Int64 DelayMethod(int maxNumber, BackgroundWorker worker, DoWorkEventArgs e)
     {
          Int64 result = 0;


          for (int i = 1; i <= maxNumber; i++)
          {
              //백그라운드 작업을 취소 했는지 검사한다.
             if (worker.CancellationPending)
             {
                  e.Cancel = true;
             }
             else
             {
                  result += i;

     

                  //진행률을 % 로 계산한다.
                  int percentComplete = (int) ((float)i / (float)maxNumber * 100);

                  if (percentComplete > highestPercentageReached)
                  {
                      highestPercentageReached = percentComplete;

     

                      //ProgressChanged 이벤트를 발생시킨다
                      //작업의 완료률을 0~100 숫자로 보고한다
                      worker.ReportProgress(percentComplete);
                   }

     

                  //지연을 위해 잠시 멈춘다
                  Thread.Sleep(100);
             }
        }       

          //수행을 마치면 결과 값을 반환한다
          return result;            
     }

     

    이제 코드 작성이 완료 되었습니다.

    첨부파일에 이 글에 사용된 샘플 프로젝트가 등록되어 있으니 다운받으셔서 직접 실행 시켜 보시기 바랍니다.

    아래 그림은 프로젝트를 실행완료한 화면 입니다.

     

    이상 닷넷 2.0 에 새로 추가된 BackgroundWorker 컴포넌트에 대해 간략히 살펴 보았습니다.

     


  • ▣  MSSTUDY.... - 개발관련 이슈 - 2009. 12. 7. 09:31

    가치있는 교육 이였다...
    비록 실력이 미천하여 다 소화하지는 못했으나 비싼 돈을 받는 강사는 다르구나...라는걸 확실히 느꼈다 ㅋㅋㅋ
    국가기관에서 우수 교육으로 선정 되어서 매년 하고 있고 내년에도 할 예정이라 하니 개발자로서 자신을 업 하고 싶은 분들에게 강추한다...(나도 내년에 가서 또 들을까....ㅋ)

    아 MSSTUDY 라는 사이트에 가보면 강의 동영상이 있다....물론 유료다^^

    .............................................................................................................................................

    지난 7월 마지막주의 뜨거운 태양 아래서 해변에서 초등학교의 마지막 여름방학을 보내야 할 아들을 뒤로 하고 교육을 받기로 결심해 놓고도 교육받기 전까지는 내내 후회가 머릿속을 떠나지 않았다. 요즘은 초등학교때부터 사교육이다 뭐다 해서 자식의 스케줄에 부모가 맞춘다고들 하는데....
     그러나 40대 중반으로 달려가다 보니, 그동안 전산밥을 먹은지 20년이 지났지만 쌓아 놓은 것 보다 앞으로 쌓아가야 할 게 많은 것이 소프트웨어의 현실이다 보니, 교육은 생존전략에 가깝다. 예전에는 1개만 배워서 많이 써먹었는데, 이제는 너무 광범위한 범위의 신기술로 인해 하루라도 손에서 책을 놓지 않으면 안되는 현실이다.

     며칠 전에는 금번교육 뿐만이 아니라 작년에 받았던 교육에 대해 설문조사에 대한 전화를 1통화 받았다. 교육의 효과에 대한 설문인데, 그동안 우리는 이런 교육에 목말라 했는지도 몰랐다고 말했다. 지난 10여년동안 회사를 운영하면서, 기존에 구축한 Visual Basic의 Application으로만 먹고 살았는데, 이제는 End-User가 정보에 뛰어나, 많은 요구사항을 Push한다. 정말 작년에 받은 교육은 그대로 프로젝트에 반영이 되어서 많은 효과를 보았다. 당사에 근무하는 직원들 뿐만이 아니라, 나 자신도 한 단계 Level Up이 된 느낌이었다.
     그러나 작년에는 근무시간에 진행되는 교육과 야간에 진행되는 교육이어서 근무시간에는 거래처에서 전화오는 것에 신경쓰느라, 야간에는 체력적인 한계를 극복하느라 시간가는 줄 몰랐었다. 아마도 배운 것은 20%이상의 Loss가 있지 않았나 싶었다.

     금번 교육은 평상시 온라인 동영상으로 교육을 받아 감명이 깊었던 프리엠컨설팅의 이충일 대표의 강의라 더욱이 기대가 높았고, 당장 프로젝트 개발하는데 사용을 하기 위해서라도 교육의 기대치는 매우 높았다. 하여 과감하게 초등학교 6학년인 아들의 마지막 여름방학기간을 선택했다. 이때는 휴가시즌이라서 거래처에서도 전화가 별로 없으리라는 기대에서 다음차수 보다는 직원들과 의기투합해서 여름휴가와 통째로 바꾼 교육이었다.

     나름대로 VisualBasic의 선두주자였던 나도 94년도에 연세의료원 및 녹십자프로젝트를 하면서 쌓은 경험으로 삼성멀티캠퍼스에서도 강의를 한 적이 있었지만, 이충일 강사의 강의는 감동을 주는 스타일이다. 결국 교육생이 원하는 것을 주는 것이 강사의 책무라고 할 수 있는 데 많은 사람의 공통적인 것은 그 교육을 받고 내가 활용할 수 있어야 한다고 생각된다. 정말 나도 사장이지만, 교육을 한달의 절반을 받고 활용할 수 없으면 교육은 더 이상의 교육이 아니라, 휴가일뿐이다. 그러나 이충일 강사는 그런 기대치를 만족시켜주었다.,
     예전에 강의했던, 또는 다른 동영상의 강의와 다른 점은 무엇일까를 나름대로 생각해 보았다.

     첫째는 개념에 대한 정립이다. 개념이 없으면 프로그램을 짜도 무엇을 짜는지 모르는 상태가 되는 것이다. 그런데, 보통 세미나를 가면 개념만 적립하다 온다. 사람의 집중력은 10초, 1분, 10분 단위라고 한다. 그런 개념은 10초, 1분, 10분만에 정립이 될 수 있어야 한다고 생각한다. 이런의미에서 짧은시간에 개념이 적립이 되지 못하면, 결국 개념과 현실은 별개의 문제가 된다.

     둘째는 적절한 예제이다. 예제를 따라하다보면, 나름 손부터 움직일 수 있으니까, 그런데 정말 개념을 적립해주는 예제, 그리고 실적에 적용할 수 있는 예제를 표현하신다.
     
    셋째는 경험에서 나오는 강의 방법이다. 아무리 좋은 강의라도 한톤의 목소리만 진행되면, 천근보다 무거운 것이 눈꺼풀이라고 했던가?

     삼박자가 맞는 강의를 들은후에 무엇인가 모를 자신감이 생겼다. 그동안 직원들과 1시간 일찍 출근해서 동영상으로 학습을 하기도 하고, 세미나를 가기도 했지만 C#과 Ajax에 자신감이 생겼다. 물론 교육을 계속 받다보면 며칠전에 받은 것은 잊어버리는 것이 당연한 사람의 책무이다. FIFO - 먼저 학습한 것이 먼저 나간다. 그러나 남는 것은 개념과 교육자료, 샘플소스가 있기 때문에 흔적을 찾아가 프로그램을 하는 것이 아닐까라고 생각된다.  

    비록 아들의 휴가를 뺏었지만, 그보다 많은 것을 얻은 교육이라 생각된다.

    설문조사가 왔을 때, 이렇게 답변했다. 다음번에는 꼭 반영해달라고하면서, 직장인이 자식을 키우고, 생활을 하면서 본인한테 교육비로 투자할 만한 여력이 얼마나 될 수 있겠느냐고 물어보았다. 아마 대부분의 소프트웨어 업체에 계시는 엔지니어는 금액도 문제지만, 시간도 문제일 것이다. 신기술이 계속 쏟아져 나오는 데 조각난 세미나에서 교육을 받는 것도 한계이고, 본인이 책을 보면서 공부한다는 것도 문제이고, 본인이 평상시 몇십만원이나 교육비를 투자하는 것도 과연 현실적으로 가능하겠는가라는 것이다.
     금액적으로도 그 많은 과목을 들으려면 1년에 몇백만원을 투자해야 하는데, 계속 성장하는 소프트웨어산업에서 오랜 경력으로 살아남으려면, 자신에게 계속 투자를 해야 되는데 그런 투자할 만한 엔지니어가 과연 얼마나 되겠느냐고 조사자한테 물어보았다, 결국 오랜 경험을 가진 풍부한 엔지니어가 자기개발을 할 기회가 없어서, 영업으로 빠지고, 다른 직종으로 빠지는 것이 우리나라의 현실이 아니겠냐고~ 또한 소프트웨어 업체도 새로운 기술을 사용하려면 이제 막 졸업한 신입사원 및 경력 2~3년차에게 프로그램을 맞기는 현실이 아니겠냐고,

     정말 소프트웨어의 지식산업을 육성하려면, 직장인, 고급기술자를 더욱 확대 하는 것이 우리나라의 경쟁력을 갖추는데에도 엄청난 자산가치가 될 수 있다고 확신한다.

     또한 교육방식에도 기존의 평일교육이라는 틀, 장소적 제한이라는 틀을 깨고 오전 일찍, 또는 토요일 주말교육을 진행하는 것이 재직자에게는 부담이 없다, 사실 야간교육은 업무적인연장선에 있기에 체력적인 한계뿐만이 아니라, 업무적 정리도 힘들다, 토요일은 나름대로 자유로운 시간이기에 토요일교육을 선호하는 게 직장인에게는 효율적이라 생각된다.

    ? 정말 이런 교육을 보다 많은 곳에서 손쉽게 들었으면 하는 것이 마지막 바람이다. 우리나라의 소프트웨어의 부흥은 결국 교육에 달린 것이 아니겠는가?

    http://image.devpia.com/NewDevpia/DevpiaStudy/Seminar/0809/kipa0901_after.htm

    ▣  4년제 대학을 1년만에 졸업한다 - etc - 2009. 12. 3. 09:22


    articles
    recent replies
    recent trackbacks
    notice
    Admin : New post