2016-09-06 6 views
2

으로 프로세스를 구현하는 동안 구현을 중지하는 방법입니다. 따라서이 코드는 임의의 시작 번호로 증가 된 값의 스트림 값을 사용합니다. start1 값이 커지고 start2보다 크면 텍스트 상자가있는 해당 줄을 표시하고 다른 줄을 표시하려고합니다.backgroundWorker

문제 주어진주기 수가 만족 될 때까지 프로그램을 멈출 수 없습니다. 주입 중에 버튼이 멈 춥니 다. 나는 이것이 일어나는 이유가 반복적이라는 것을 이해한다. 이제 backgroundWorker로 중지하려고하지만 같은 결과가 나타나면 취소 단추가 같은 방법으로 중지됩니다.

backgroundWorker1_ProgressChanged 내에 위치한 backgroundWorker와 함께 사용하려는 코드. 나는 여기서 무슨 일이 일어나고 있는지 정말로 이해하지 못한다. 어쩌면 당신은 내가 잘못 뭘하는지 파악하는 데 도움이 :

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

namespace XX_8_0 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
      backgroundWorker1.WorkerReportsProgress = true; 
      backgroundWorker1.WorkerSupportsCancellation = true; 
     } 

     private void startAsyncButton_Click(object sender, EventArgs e) 
     {  
      if (backgroundWorker1.IsBusy != true) 
      { 
       backgroundWorker1.RunWorkerAsync(); 
      } 
     } 

     private void cancelAsyncButton_Click(object sender, EventArgs e) 
     { 
      if (backgroundWorker1.WorkerSupportsCancellation == true) 
      { 
       backgroundWorker1.CancelAsync(); 
      } 
     } 

     private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
     { 
      BackgroundWorker worker = sender as BackgroundWorker; 

      for (int i = 1; i <= 10; i++) 
      { 
       if (worker.CancellationPending == true) 
       { 
        e.Cancel = true; 
        break; 
       } 
       else 
       { 
        System.Threading.Thread.Sleep(500); 
        worker.ReportProgress(i * 10); 
       } 
      } 
     } 

     private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      var random = new Random(); 
      var start1 = random.Next(0, 100); 
      var start2 = random.Next(0, 100); 
      var incrementor1 = start1 > 50 ? -1 : 1; 
      var incrementor2 = start2 > 50 ? -1 : 1; 
      var cV1 = start1; 
      var cV2 = start2; 

      for (var i = 0; i < 1000; i++) 
      { 
       if (cV1 == 101) incrementor1 = -1; 
       if (cV1 == 0) incrementor1 = 1; 

       if (cV2 == 101) incrementor2 = -1; 
       if (cV2 == 0) incrementor2 = 1; 

       if (cV1 > cV2) 
       { 
        textBox1.AppendText("ID: (" + i + ") CV1: (1): [" + cV1 + "] CV2: (0) [" + cV2 + "]\n"); 
       } 
       else 
       { 
        textBox1.AppendText("ID: (" + i + ") CV1: (0): [" + cV1 + "] CV2: (1) [" + cV2 + "]\n"); 
       } 

       cV1 += incrementor1; 
       cV2 += incrementor2; 
      } 
     } 
     private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      if (e.Cancelled == true) 
      { 
       resultLabel.Text = "Canceled!"; 
      } 
      else if (e.Error != null) 
      { 
       resultLabel.Text = "Error: " + e.Error.Message; 
      } 
      else 
      { 
       resultLabel.Text = "Done!"; 
      } 
     }  
    } 
} 
+0

내 대답 외에도 ** 관련 ** 섹션에서 유용한 정보를 얻을 수 있습니다. 분명히 위의 구현은 매우 좋지 않으며'BackgroundWorker'가 어떻게 작동하는지 잘 이해하지 못하고 있습니다. – Phil1970

답변

3

을 : 당신의 예를 정말 아마도 BackgroundWorker가 할 수있는 좋은 예가 아니다라고 생각합니다. 본질적으로 당신의 코드는 약간 잠들고 다른 스레드에서는 거의 유용하지 않다.


귀하의 backgroundWorker1_ProgressChanged 약간의 시간이 걸릴 수 따라서 1000 textBox1.AppendText()을 추가하고 꽤 무겁습니다.

버튼 이식 중에 버튼이 멈 춥니 다. 나는 이것이 일어나는 이유가 반복적이라는 것을 이해한다.

당신이 backgroundWorker1_ProgressChanged 상관없이 backgroundWorker1_ProgressChanged 돌아갈 때까지 처리되지 않습니다 취소에 당신이 만드는 어떤 클릭 수, UI 스레드에서 실행되지 않습니다 고려

. 모든 UI 처리는 UI 스레드가 수행해야합니다. 백그라운드 작업자 스레드도이 시간 동안 일시 중단되며 유감스럽게도 취소를 테스트하는 코드의 유일한 부분이라고 지적해야합니다. ReportProgress이 비동기 인 경우에도 취소 단추 이벤트를 처리하고 작업을 CancellationPending으로 표시하려면 UI 스레드가 필요합니다.

난 당신이 backgroundWorker1_ProgressChanged에서 한 번에 많은 것을보고하거나 아마도 textBox1로 배치에보고 추가 항목을 고려하지 않는 것이 좋습니다.

그런 식으로 메시지 펌프와 응용 프로그램의 응답 성을 높일 수 있습니다.

backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 배치를 사용하도록 변경

로 : 당신의 ProgressChanged 핸들러가 1000 배 호출 ReportProgress 당에 대한 UI를 업데이트하는 매우 바쁜 때문에

var builder = new StringBuilder(); 

for (var i = 0; i < 1000; i++) 
{ 
    if (cV1 == 101) incrementor1 = -1; 
    if (cV1 == 0) incrementor1 = 1; 

    if (cV2 == 101) incrementor2 = -1; 
    if (cV2 == 0) incrementor2 = 1; 

    if (cV1 > cV2) 
    { 
     builder.Append("ID: (" + i + ") CV1: (1): [" + cV1 + "] CV2: (0) [" + cV2 + "]\n"); 
    } 
    else 
    { 
     builder.Append("ID: (" + i + ") CV1: (0): [" + cV1 + "] CV2: (1) [" + cV2 + "]\n"); 
    } 

    cV1 += incrementor1; 
    cV2 += incrementor2; 
} 

textbox1.AppendText(builder.ToString()); 
+0

글쎄, 나는 아주 나쁜 성능을 받았고, _worker.ReportProgress_를 통해 _backgroundWorker1_DoWork_에 내 코드를 넣는다면, 무엇을해야할지 잘 모르겠다. 오류가 발생하면 –

+0

나는 그 점을 매우 의심한다. 더 빨라질 것 같아요? 하나의'AppendText()'또는 ** 1000 x **'AppendText()'? 호출 스택이 다른 스레드 (배경 작업자의'ReportProgress')에서 비롯된 경우에도 대부분의 CPU 시간이 AppendText()에 소비되고 있습니다. – MickyD

0

, 그것은 모든 UI 스레드 CPU 시간을 사용하고 스레드 것 이미 너무 바빠서 취소 버튼을 처리 할 수 ​​없습니다.

BackgroundWorker을 사용한다고 가정하면 핸들러에서 대부분 ProgressChanged을 옮기고 배경 스레드에서 해당 수면을 제거해야합니다.

방법을 사용하면 BackgroundWorker은 이해가되지 않습니다. UI 스레드는 가능한 한 작게해야하며 배경 스레드는 가능한 한 많이해야합니다.그리고 배경 작업이 경과 된 시간에 의존하지 않기 때문에 배경 스레드에서 잠을 자면 의미가 없습니다.

일단 코드가 이동되면 데이터를 다시 UI 스레드로 보내야합니다. 그러나 이것은 UI 객체에 UI 객체를 전달할 수있는 ReportProgress의 오버로드가 있기 때문에 매우 쉽습니다 (일반적으로 UI 스레드에서 백그라운드 작업자가 생성되었다고 가정). 다른면에서는 사용자 데이터를 적절한 유형으로 변환하고 해당 정보를 사용하여 텍스트 상자에 적절한 텍스트를 추가합니다.

향상된 코드를 사용하면 데이터를 훨씬 빠르게 처리 할 수 ​​있습니다. 그런데 StringBuilder도 문자열을 작성하는 데 사용해야합니다. 사실 UI 텍스트를 1000 번 업데이트하는 횟수가 적기 때문에 UI 성능에 큰 영향을 미쳐야합니다.