BackgroundWorker 및 백그라운드 스레드


166

Windows Form 앱에서 사용해야하는 백그라운드 스레드 구현의 선택에 대한 문체 질문이 있습니다. 현재 BackgroundWorker무한 (while(true))루프 가있는 양식이 있습니다 . 이 루프에서는 WaitHandle.WaitAny관심있는 일이 발생할 때까지 스레드를 다시 알림을 유지하는 데 사용합니다. 내가 기다리는 이벤트 핸들 중 하나는 " StopThread"이벤트이므로 루프에서 벗어날 수 있습니다. 이 이벤트는 재정의 된 시점에서 알립니다 Form.Dispose().

BackgroundWorker파일을 다운로드하거나 일련의 항목을 처리하는 것과 같이 UI를 묶고 싶지 않은 유한 한 작업을 위해 실제로 작성된 곳을 읽었 습니다. 이 경우 "종료"는 알 수 없으며 창을 닫을 때만 가능합니다. 따라서이 BackgroundWorker목적 대신 배경 스레드를 사용하는 것이 더 적절 합니까?

답변:


88

귀하의 질문에 대한 나의 이해 BackgroundWorker에서 표준 스레드로 사용하고 있습니다.

BackgroundWorkerUI 스레드를 묶고 싶지 않은 것들에 권장되는 이유 는 Win Forms 개발을 수행 할 때 멋진 이벤트가 노출되기 때문입니다.

같은 이벤트는 RunWorkerCompleted스레드가 그것을 할 필요가 무엇 완료되면 알리기 위해, 그리고 ProgressChanged스레드가 진행에 이벤트가 GUI를 업데이트 할 수 있습니다.

당신이 경우에 따라서 하지 않는 이들의 활용, 당신이해야 할 일에 대한 표준 스레드를 사용하여 어떤 해를 볼 수 없습니다.


내가 확신하지 못하는 또 다른 문제는 백그라운드 워커가 실행중인 양식을 처분하려고한다고 가정합니다. 종료 이벤트 (ManualResetEvent)를 알리고 DoWork가 정상적으로 종료됩니다. DoWork가 완료하는 데 시간이 조금 더 걸리더라도 스레드를 처리하는 데 약간의 시간이 걸리거나 더 나은 방법이 있더라도 양식을 계속 진행하고 처분해야합니까? 백그라운드 작업자가 실제로 종료 될 때까지 참여한 다음 Dispose 형태의 계속?
프레디 스미스

나는 BackgroundWorker.IsBusy가 당신이 찾고있는 것이라고 생각합니다.
ParmesanCodice

1
만 사용 CancelAsync을위한 (테스트 CancellationPending대신, 용도 제기 예외가 원하는 경우 스레드가, 짧은 간격에 폴링 될 경우 System.Threading.Thread.Abort()스레드 블록 자체 내에서 예외가 발생하는을, 상황에 맞는 모델을 선택합니다.
브렛 라이언

369

내 생각 중 일부는 ...

  1. 백그라운드 에서 실행되는 단일 작업이 있고 UI와 상호 작용해야하는 경우 BackgroundWorker를 사용하십시오 . UI 스레드에 대한 데이터 마샬링 및 메서드 호출 작업은 이벤트 기반 모델을 통해 자동으로 처리됩니다. 다음과 같은 경우 BackgroundWorker를 피하십시오.
    • 어셈블리에 UI가 없거나 직접 상호 작용하지 않는 경우
    • 스레드가 포 그라운드 스레드 여야합니다. 또는
    • 스레드 우선 순위를 조작해야합니다.
  2. 효율성이 필요한 경우 ThreadPool 스레드를 사용하십시오 . ThreadPool은 스레드 작성, 시작 및 중지와 관련된 오버 헤드를 방지합니다. 다음과 같은 경우 ThreadPool을 사용하지 마십시오.
    • 작업은 애플리케이션 수명 동안 실행됩니다.
    • 스레드가 포 그라운드 스레드가되어야합니다.
    • 스레드 우선 순위를 조작하거나
    • 고정 된 ID (중지, 일시 중단, 발견)를 갖기 위해서는 스레드가 필요합니다.
  3. 장기 실행 작업 및 공식 스레딩 모델에서 제공하는 기능 (예 : 포 그라운드 및 백그라운드 스레드 선택, 스레드 우선 순위 조정, 스레드 실행에 대한 세밀한 제어 등)이 필요한 경우 Thread 클래스를 사용하십시오 .

10
백그라운드 작업자는 System.dll 어셈블리 및 System.ComponentModel 네임 스페이스에 있습니다. Winforms에 대한 종속성이 없습니다.
Kugel

17
맞지만 BackgroundWorker스레드 진행 상황을 이해 당사자 (일반적으로 UI 포함)에게보고하도록 설계되었습니다. 클래스에 대한 MSDN 설명서는이를 명확하게 보여줍니다. 백그라운드에서 수행해야 할 작업이 필요한 경우 ThreadPool스레드를 사용하는 것이 좋습니다.
Matt Davis

5
System.Windows.Forms집회 에 대한 당신의 요점과 관련하여 ; BackgroundWorkerWPF 앱에도 유용하며 해당 앱에 WinForms에 대한 참조가 없을 수 있습니다.
GiddyUpHorsey

12

Matt Davis가 말한 내용은 다음과 같습니다.

나에게있어 가장 큰 차이점 BackgroundWorker은를 통해 완료된 이벤트를 자동으로 마샬링하는 것 SynchronizationContext입니다. UI 컨텍스트에서 이는 완료된 이벤트가 UI 스레드에서 발생하므로 UI를 업데이트하는 데 사용될 수 있음을 의미합니다. BackgroundWorkerUI 컨텍스트에서를 사용하는 경우 이는 주요 차별화 요소 입니다.

를 통해 실행 된 작업 ThreadPool은 쉽게 취소 할 수 없습니다 ( ThreadPool. QueueUserWorkItem및 대리자가 비동기 적으로 실행 포함 ). 따라서 스레드 스핀 업의 오버 헤드를 피하면서 취소가 필요한 경우 BackgroundWorker또는 UI를 사용하여 스레드를 스핀 업하고 참조를 유지하여 호출 할 수 있도록하십시오 Abort().


1
응용 프로그램이 스레드 된 작업을 중지 하는 깔끔한 방법에 대해 설계

11

또한 백그라운드 워커의 수명 동안 스레드 풀 스레드를 묶습니다. 유한 한 수의 스레드 만 있으므로 문제가 될 수 있습니다. 앱에 스레드를 한 번만 만들고 백그라운드 작업자의 기능을 사용하지 않는 경우 backgroundworker / threadpool 스레드 대신 스레드를 사용한다고 말하고 싶습니다.


1
나는 이것이 좋은 지적이라고 생각합니다. 따라서 내가 보낸 메시지는 양식 수명 동안 "일시적으로"배경 스레드가 필요한 경우 백그라운드 작업자를 사용하는 것이지만 양식의 전체 수명 (분, 시간, 일 ...) 다음 그래서 ThreadPool이 아닌 오용 목적에로 대신 BackgroundWorker에의 스레드를 사용
프레디 스미스

에 관하여 : "... 이것은 유한 한 수가 있기 때문에 우려 할 수 있습니다", 당신은 OS의 다른 앱이 필요하고 동일한 '풀'에서 공유 할 수 있음을 의미합니까?
Dan W

8

Windows Forms, WPF 또는 기타 기술을 사용하는지 여부에 관계없이 BackgroundWorker로 작업하는 것이 더 쉬운 경우도 있습니다. 이 사람들의 깔끔한 부분은 스레드가 실행되는 위치에 대해 너무 걱정할 필요없이 스레딩을 얻는 것입니다. 이는 간단한 작업에 좋습니다.

BackgroundWorker스레드 (클로징 앱, 사용자 취소)를 취소하려면 먼저 고려 사항을 사용하기 전에 스레드가 취소를 검사해야하는지 또는 실행 자체에 추력을할지 결정해야합니다.

BackgroundWorker.CancelAsync()설정합니다 CancellationPending으로 true는 지속적으로이를 확인하면 사용자가 취소 이러한 접근 방식의 경쟁 조건으로 끝날 수 있다는 것을 염두에 두어야하지만, 스레드가 테스트 이전에 완료에 다음 스레드 책임하지만, 더 아무것도하지 않습니다 CancellationPending.

Thread.Abort() 반면에 스레드 실행 내에서 예외가 발생하여 해당 스레드가 취소되므로이 예외가 실행 내에서 갑자기 발생하면 위험한 상황에주의해야합니다.

스레딩은 어떤 작업을 수행하든 추가로 읽으려면 매우 신중하게 고려해야합니다.

.NET Framework 관리 형 스레딩 모범 사례 의 병렬 프로그래밍


5

.NET을 알기 전에 스레드를 사용하는 방법을 알았으므로 BackgroundWorkers를 사용하기 시작했을 때 익숙해졌습니다 . Matt Davis는 그 차이점을 매우 우수하게 요약했지만 코드가 수행하는 작업을 정확히 이해하기가 더 어려워 디버깅이 더 어려워 질 수 있다고 덧붙였습니다. 스레드 풀에 작업을 제공하는 것보다 IMO라는 스레드 작성 및 종료에 대해 생각하는 것이 더 쉽습니다.

여전히 다른 사람들의 게시물에 댓글을 달 수 없으므로 교각을 해결하기 위해 답변을 사용하는 순간적인 절름발이를 용서하십시오 7

Thread.Abort();대신 사용하지 말고 이벤트에 신호를 보내고 신호를 받으면 스레드가 정상적으로 종료되도록 설계하십시오. Thread.Abort()a는 제기 ThreadAbortException등 고아 모니터, 손상된 공유 상태 및 같은 불행한 모든 종류의 것들을 할 수있는 스레드의 실행의 임의의 점에서.
http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx


2

그것이 깨지지 않은 경우-농담 할 때까지 고치십시오 : 농담 :)

그러나 심각하게 BackgroundWorker는 아마도 이미 가지고있는 것과 매우 유사 할 것입니다. 처음부터 시작했다면 아마도 시간을 절약했을 것입니다. 그러나이 시점에서 나는 필요를 보지 못했습니다. 무언가가 작동하지 않거나 현재 코드가 이해하기 어렵다고 생각하지 않으면 가지고있는 것을 고수 할 것입니다.


2

기본적인 차이점은 위에서 언급 한 것처럼에서 GUI 이벤트를 생성하는 것 BackgroundWorker입니다. 스레드가 디스플레이를 업데이트하거나 기본 GUI 스레드에 대한 이벤트를 생성 할 필요가없는 경우 간단한 스레드 일 수 있습니다.


2

아직 언급되지 않은 BackgroundWorker 클래스의 한 가지 동작을 지적하고 싶습니다. Thread.IsBackground 속성을 설정하여 백그라운드에서 일반 스레드를 실행하도록 만들 수 있습니다.

백그라운드 스레드는 프로세스가 종료되는 것을 방지하지 않는다는 점을 제외하면 포 그라운드 스레드와 동일합니다. [ 1 ]

양식 창의 생성자에서 다음 메소드를 호출하여이 동작을 테스트 할 수 있습니다.

void TestBackgroundThread()
{
    var thread = new Thread((ThreadStart)delegate()
    {
        long count = 0;
        while (true)
        {
            count++;
            Debug.WriteLine("Thread loop count: " + count);
        }
    });

    // Choose one option:
    thread.IsBackground = true; // <--- This will make the thread run in background
    thread.IsBackground = false; // <--- This will delay program termination

    thread.Start();
}

IsBackground 속성이 true로 설정되고 창을 닫으면 응용 프로그램이 정상적으로 종료됩니다.

그러나 IsBackground 속성이 기본적으로 false로 설정되어 있고 창을 닫으면 창만 사라지지만 프로세스는 계속 실행됩니다.

BackgroundWorker 클래스는 백그라운드에서 실행되는 Thread를 사용합니다.


1

백그라운드 작업자는 별도의 스레드에서 작동하는 클래스이지만 간단한 스레드로는 얻을 수없는 추가 기능 (작업 진행 보고서 처리와 같은)을 제공합니다.

백그라운드 작업자가 제공 한 추가 기능이 필요하지 않고 필요하지 않은 것 같다면 Thread가 더 적합합니다.


-1

나에게 당황한 점은 Visual Studio 디자이너가 실제로 서비스 프로젝트에서 작동하지 않는 BackgroundWorkers 및 Timer 만 사용할 수 있다는 것입니다.

그것은 당신에게 서비스로 깔끔한 드래그 앤 드롭 컨트롤을 제공하지만 배포하려고 시도조차하지 마십시오. 작동하지 않습니다.

서비스 : System.Timers.Timer 만 사용 System.Windows.Forms.Timer는 도구 상자에서 사용할 수 있지만 작동하지 않습니다.

서비스 : BackgroundWorkers가 서비스로 실행될 때 작동하지 않음 System.Threading.ThreadPools를 대신 사용하거나 비동기 호출

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.