C # BackgroundWorker получить результаты - PullRequest
0 голосов
/ 15 марта 2011

Как мне получить результаты от BackgroundWorker в этом случае?Я также открыт для альтернативных действий (например, не использовать BackgroundWorker).Цель состоит в том, чтобы выполнять всю мою работу параллельно, начиная одновременно.Я на самом деле честно не знаю, будут ли все работы выполняться параллельно с помощью bw.Я все еще изучаю этот материал.Я использую WPF / XAML (я почти уверен, что это имеет большое значение для написания кода типа многопоточности).

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 ]

2 голосов
/ 15 марта 2011

Вы можете попробовать Task в .NET 4.0 System.Threading.Tasks

После вызова StartNew основной поток продолжает параллельно делать то, что вы хотите, затем один раздостигает точки, где в главном потоке требуется возвращаемое значение, основной поток блокируется до тех пор, пока результат не будет возвращен методом, вызванным в другом потоке.Если результат уже возвращен основным потоком, достигнет WriteLine, блокировка отсутствует.

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

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

ИЛИ

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

Проверьте этот блог на наличие более интересных примеров.*

РЕДАКТИРОВАТЬ

После нижеследующего (довольно разочаровывающего) обсуждения мне пришлось внести изменения в этот ответ, чтобы обосновать правильный ответ.

в .NET Framework 4, задачи являются предпочтительным API для написания многопоточного, асинхронного и параллельного кода. Проверка MSDN

1 голос
/ 15 марта 2011

Лучше всего, чтобы все это работало асинхронно. Если вы не дадите runWorkers вернуться до тех пор, пока все рабочие не будут выполнены, то вы откажетесь от основного преимущества асинхронных операций, заключающегося в том, что вы можете делать другие вещи (например, реагировать на другие события), пока они работают.

Несколько предложений на этот счет:

  1. Создайте коллекцию ObservableCollection для хранения отчетов. С наблюдаемыми коллекциями вы можете привязать к нему элементы пользовательского интерфейса, и они будут автоматически обновляться при изменении коллекции. Также возможно программно захватить событие CollectionChanged коллекции, если вам нужно знать, когда оно изменяется. Однако, предостережение - никогда не изменяйте эту коллекцию изнутри процедуры DoWork!

  2. Вам нужно будет создать различный BackgroundWorker для каждого отчета. Если вы попытаетесь запустить уже работающий BackgroundWorker, вы получите исключение. Однако следует помнить, что одновременный запуск очень большого числа BackgroundWorkers может привести к небольшому перебою в работе системы. В этих случаях вы можете использовать ThreadPool .

  3. Присоедините обработчик события RunWorkerCompleted к каждому BackgroundWorker. Этот обработчик события должен распаковать результаты свойства Result объекта RunWorkerCompletedEventArgs и добавить его в коллекцию. Если 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);
    }
}
...