2011-03-15 69 views
0

在這種情況下,如何從BackgroundWorker獲取結果?我也願意以其他方式做事(比如不使用BackgroundWorker)。我們的目標是同時開展所有工作。我真的不知道是否所有的工作都會使用bw並行完成。我仍然在學習這個線程化的東西。我使用的是WPF/XAML(我非常確定這對編寫線程類型代碼有很大的影響)。C#BackgroundWorker獲得結果

namespace JobFactory 
{ 
    public partial class MainWindow : Window 
    { 
     MainWindow() 
     { 
      InitializeComponent(); 
      Manager boss = new Manager(); 
      string[] reports = boss.runWorkers(50); 
     } 
    } 

} 
namespace Workers 
{ 
    class Manager 
    { 
     public reports[] runWorkers(int numWorkers) 
     { 
      BackgroundWorker worker = new BackgroundWorker(); 

      for (int i = 0; i < numWorkers; i++) 
      { 
       worker.DoWork += delegate(object s, DoWorkEventArgs args) 
       { 
        string report = this.job(); 
       }; 
      } 

      worker.RunWorkerAsync(); 

      //Return reports here... 
     } 

     public string job() 
     { 
      Thread.Sleep(2000); 
      return "Job Completed"; 
     } 
    } 
} 

回答

2

你可以嘗試任務在.NET 4.0中System.Threading.Tasks

後你叫StartNew主線程繼續並行做任何你想要它做的事情,然後一旦達到一個地步,需要在主返回值線程,主線程被阻塞,直到Result被另一個線程調用的方法返回。如果主線程已經返回結果到達WriteLine,則不會阻塞。

Task task = Task.Factory.StartNew(SomeMethod); 
Console.WriteLine(task.Result); 

public static string SomeMethod() 
{ 
    return "Hello World"; 
} 

OR

Task task = Task.Factory.StartNew(() => { return "Hello World"; }); 
Console.WriteLine(task.Result); 

Check this blog for more interesting samples.

編輯

以下後(而不是沮喪)的討論,我不得不進行編輯這個答案來證明一個正確的答案。

在.NET Framework 4中,任務是編寫多線程,異步和並行代碼的首選API。檢查MSDN

+0

寫代碼上面的並行他應該使用'Parallel'類。通過這種方式,他只創建異步方法,異步!=並行。 – 2011-03-15 18:23:04

+0

小心解釋downvote? – 2011-03-15 18:23:32

+0

你能解釋一下async!= parallel嗎? – 2011-03-15 18:24:01

1

最好的辦法是讓整個事情異步運行。如果你不讓runWorkers返回,直到所有的工作都完成了,那麼你就放棄了異步操作的主要好處,那就是你可以在運行時做其他事情(比如響應其他事件)。

達成目標的幾點建議:

  1. 創建一個ObservableCollection舉行的報告。通過可觀察的集合,您可以將UI元素綁定到該元素,並隨着集合更改而自動更新。如果您需要知道集合的更改時間,還可以通過編程捕獲集合的CollectionChanged事件。但請注意,從不在DoWork過程中修改此集合!

  2. 您需要爲每個報告創建一個不同的BackgroundWorker。如果你嘗試運行已經工作的BackgroundWorker,你會得到一個異常。但是,請注意,同時啓動大量的BackgroundWorkers可能會導致系統抖動一些。在這些情況下,您可能需要使用ThreadPool來代替。

  3. 將RunWorkerCompleted事件處理程序附加到每個BackgroundWorker。此事件處理程序應解壓縮RunWorkerCompletedEventArgs的Result屬性的結果,並將其添加到集合中。如果BackgroundWorker在主線程中啓動,則該事件將保證在主線程中引發,因此從該事件處理程序更新集合應該是安全的。

這裏有一個如何做到這一點的草圖:

class Manager 
{ 
    public ObservableCollection<string> Reports { get; private set; } 

    public void runWorkers(int numWorkers) 
    { 
     for (int i = 0; i < numWorkers; i++) 
     { 
      BackgroundWorker worker = new BackgroundWorker(); 

      worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
      worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); 
      worker.RunWorkerAsync(i); 
     } 
    } 

    void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     e.Result = Job((int)e.Argument); 
    } 

    public void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if(e.Error != null) 
     { 
      // handle error 
     } 
     else 
     { 
      Reports.Add(e.Result as string); 
     } 
    } 

    private string Job(int jobID) 
    { 
     Thread.Sleep(2000); 
     return string.Format("Job {0} Completed", jobID); 
    } 
} 
+0

我很想下決心。該代碼包含一個空的catch子句。 – 2011-03-15 19:25:21

+0

我說過粗略的草圖。雖然我不確定你在哪裏看到空的catch條款。在worker_DoWork()內部發生的任何異常都會被自動捕獲並通過e.Error傳遞給worker_RunWorkerCompleted()。在該處理程序中,如果e.Error不爲null,則在評估e.Result時會引發異常。 – 2011-03-15 21:44:32

+0

當我看到一個不檢查e.Error的Completed處理程序時,我總是發表一個評論。但是你對e.Result加入是正確的,我錯過了。雖然不會使用它。 – 2011-03-15 22:26:48