How do I get results from the BackgroundWorker in this case? I'm also open to doing things in in alternative manner(such as not using BackgroundWorker). The goal is to do all my jobs in parallel, starting at the same time. I actually honestly don't know if all jobs will be completed in parallel using bw. I'm still learning this threading stuff. I'm using WPF/XAML (I'm pretty sure that makes a big difference on how threading type code is written).
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";
}
}
}
You could try Task in .NET 4.0 System.Threading.Tasks
After you call StartNew
main thread continues in parallel doing whatever you want it to do, then once it reaches a point where return value is required in Main Thread, main thread is blocked till the Result is returned by the method called on the other thread. If the result is already returned by the main thread reaches the WriteLine there is no blocking.
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.
EDIT
After below (rather frustrating) discussion I had to make an edit to this answer to justify a right answer.
in the .NET Framework 4, tasks are the preferred API for writing multi-threaded, asynchronous, and parallel code. Check MSDN
Your best bet is to let the whole thing run asynchronously. If you don't let runWorkers return until all the workers are done, then you're giving up the primary benefit of asynchronous operations, which is that you can do other things (like respond to other events) while they're running.
A few suggestions toward that end:
Create an ObservableCollection to hold the reports. With observable collections, you can bind UI elements to it and they will automatically update as the collection changes. It is also possible to programmatically capture the collection's CollectionChanged event if you need to know when it changes. A word of caution, though - never modify this collection from inside the DoWork procedure!
You will need to create a different BackgroundWorker for each report. If you try to run a BackgroundWorker that's already working, you'll get an exception. However, be aware that starting a very large number of BackgroundWorkers simultaneously might cause the system to thrash a bit. In those cases you might want to look into using ThreadPool instead.
Attach a RunWorkerCompleted event handler to each BackgroundWorker. This event handler should unpack the results of the RunWorkerCompletedEventArgs's Result property, and add it to the collection. If the BackgroundWorker was started on the main thread, then this event is guaranteed to be raised on the main thread, so it should be safe to update the collection from this event handler.
Here's a rough sketch of how you might do it:
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);
}
}
精彩评论