Какой самый простой способ реализовать многопоточность в C # для существующего кода - PullRequest
2 голосов
/ 08 января 2011

Я уже внедрил функциональное приложение, которое одновременно анализирует 26 страниц html, чтобы создать xml-файл с данными, содержащимися на веб-страницах.Мне нужно было бы реализовать поток, чтобы этот метод мог работать в фоновом режиме, не заставляя мое приложение казаться не отвечающим.

Во-вторых, у меня есть другая функция, которая отделена от первой, которая сравнивает два xml-файла для созданиятретий, а затем преобразуйте этот третий XML-файл, чтобы создать HTML-страницу, используя XSLT.Это должно быть в потоке, где я могу нажать Отмена, чтобы остановить поток без сбоев приложения.

Какой самый простой способ сделать это с использованием форм WPF в VS 2010?

Я решил использовать BackgroundWorker.

Реализация BackgroundWorker:

public partial class MainWindow : Window
    {
        private BackgroundWorker bw = new BackgroundWorker();

        public MainWindow()
        {
            InitializeComponent();
            bw.WorkerReportsProgress = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.LoadFiles();
        }

        private void btnCompare_Click(object sender, EventArgs e)
        {
            if (bw.IsBusy != true)
            {
                progressBar2.IsIndeterminate = true;
                // Start the asynchronous operation.
                bw.RunWorkerAsync();
            }

        }

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            StatsProcessor proc = new StatsProcessor();
            if (lstStatsBox1.SelectedItem != null)
                if (lstStatsBox2.SelectedItem != null)
                    proc.CompareStats(lstStatsBox1.SelectedItem.ToString(), lstStatsBox2.SelectedItem.ToString());
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            progressBar2.IsIndeterminate = false;
            progressBar2.Value = 100;
        }

Я начал с решения bgworker, но, похоже, чтометод bw_DoWork никогда не вызывается при щелчке btnCompare, я должен что-то делать не так ... Я новичок в потоках.

Ответы [ 3 ]

2 голосов
/ 08 января 2011

Если вы новичок в потоках, я думаю, что проще всего начать с использования BackgroundWorker :

  • Он использует другой поток: вы можете асинхронно выполнять анализ HTML, пока ваше приложение остается отзывчивым
  • Он поддерживает отмену: вы можете отменить преобразование XML в HTML

BackgroundWorker основан на событиях, поэтому намного проще опередить его, если вы новичок в многопоточности. Библиотека задач .NET 4 гораздо более гибкая, но немного более сложная, особенно для использования обновлений пользовательского интерфейса.

Пример:

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler((o, args) =>
{
    //Long running stuff here       
    Thread.Sleep(10000);
    string result = "Hi UI!";
    args.Result = result;
});

worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler((o, args) =>
{
    if (args.Result != null)
    {
        SomeTextBox.Text = args.Result;
    }
});

worker.RunWorkerAsync();
1 голос
/ 08 января 2011

Поскольку вы используете .NET 4 и VS2010, я бы использовал библиотеку параллельных задач.Вот пример, который показывает основы того, как фоновая задача и маршал обновления пользовательского интерфейса обратно в графический интерфейс.Я думаю, что вам нужно использовать BlockingCollection для реализации второй части.

Есть хороший пост в блоге, в котором рассказывается о цепочечных задачах и поддержке отмены: http://blogs.msdn.com/b/csharpfaq/archive/2010/08/12/blocking-collection-and-the-producer-consumer-problem.aspx

Вот пример использования без фонового рабочего

MainWindow.xaml- это просто окно с меткой статуса.Минимум, необходимый для получения балла:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Width="378" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="94" SizeToContent="Height">
    <Grid>
        <StackPanel>
            <Button Click="Button_Click">Press Me</Button>
            <StatusBar>
                <Label Name="TheLabel" Content="Status" />
            </StatusBar>
        </StackPanel>
    </Grid>
</Window>

Вот код, лежащий в основе:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading.Tasks;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // Dispatchers are an easy way to update the UI from a background thread
        private System.Windows.Threading.Dispatcher Dispatcher;

        // the Current Task - think of this as your background worker
        private Task CurrentTask;


        public MainWindow()
        {
            InitializeComponent();

            // this line needs to run on the main thread.

            Dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
        }

        private void UpdateStatus(string msg)
        {
            // marshall the call back to the main thread
            Dispatcher.Invoke( new Action( () => TheLabel.Content = msg ));
        }

        // we're going to calculate the average of a sh*tload (technical term) of numbers
        private void DoSomeWork()
        {
            // update the UI
            UpdateStatus("Doing Work");

            Random r = new Random();
            int max = r.Next(100000000, 1000000000);
            double avg = Enumerable.Range(0, max).Average();

            // update the UI
            UpdateStatus(string.Format("Done - Average = {0}", avg));
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // make sure the current task isn't already running
            if (CurrentTask != null && CurrentTask.IsCompleted == false)
            {
                MessageBox.Show("Wait");
                return;
            }

            // start a new one
            CurrentTask = Task.Factory.StartNew(() =>
                {
                    DoSomeWork();
                });
        }
    }
}
0 голосов
/ 08 января 2011

Вы можете легко сделать многопоточность, используя Threadpools . Тем не менее, неприятности и проблемы у вас будут все, что связано с вашим кодом, который создает этот файл XML. Если вы ограничите выполнение этого кода только одним потоком за раз - но ваш пользовательский интерфейс все еще реагирует, у вас будет меньше проблем с вашим кодом. (Вместо того, чтобы пытаться запустить поток и обрабатывать несколько веб-страниц одновременно)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...