Хотите использовать Task Parallel Library с отчетами о проделанной работе для обновления базы данных

Я разработал приложение, в котором хранятся несколько строк подключения. я просто повторяю цикл for и соединяю каждую базу данных и выполняю sql против каждой базы данных. таким образом, я обновляю несколько баз данных с помощью массового оператора SQL.

Теперь мне нужно использовать Task Parallel Library для одновременного обновления нескольких дБ вместо обновления один за другим в цикле. Я также хочу обработать исключение, а также хочу показать несколько индикаторов выполнения для нескольких операций базы данных. Пауза & функциональность резюме должна быть там.

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

любой может подсказать мне пример кода, как это сделать с помощью TPL. здесь я получил один код, который обновляет один индикатор, но мне нужно обновить несколько индикаторов. int iterations = 100;

ProgressBar pb = new ProgressBar();   
pb.Maximum = iterations;   
pb.Dock = DockStyle.Fill;   
Controls.Add(pb);   

Task.Create(delegate   
{   
    Parallel.For(0, iterations, i =>  
    {   
        Thread.SpinWait(50000000); // do work here   
        BeginInvoke((Action)delegate { pb.Value++; });   
    });   
}); 
ОБНОВЛЕНИЕ Вопрос

Я сделал это таким образом. код работает, но все значения индикатора выполнения увеличиваются последовательно. У меня есть одна форма и один пользовательский элемент управления в приложениях winform. пожалуйста, посмотрите на мой код и скажите, что там не так.

главное для кода
public partial class Main : Form
    {
        public Main()
        {
            InitializeComponent();
            this.DoubleBuffered = true;
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            Progress ucProgress = null;
            Dictionary dicList = new Dictionary();
            dicList.Add("GB", "conn1");
            dicList.Add("US", "conn2");
            dicList.Add("DE", "conn3");
            fpPanel.Controls.Clear();

            Task.Factory.StartNew(() =>
            {
                foreach (KeyValuePair entry in dicList)
                {
                    ucProgress = new Progress();
                    ucProgress.Country = entry.Key;
                    ucProgress.DBConnection = entry.Value;

                    fpPanel.BeginInvoke((MethodInvoker)delegate
                    {
                        fpPanel.Controls.Add(ucProgress);
                        ucProgress.Process();
                    });
                    //fpPanel.Controls.Add(ucProgress);


                    System.Threading.Thread.SpinWait(5000000);
                }
            });

        }

        private void Main_Resize(object sender, EventArgs e)
        {
            this.Invalidate();
        }
        private void Main_Paint(object sender, PaintEventArgs e)
        {
            using (LinearGradientBrush brush = new LinearGradientBrush(this.ClientRectangle,
                                                               Color.WhiteSmoke,
                                                               Color.LightGray,
                                                               90F))
            {
                e.Graphics.FillRectangle(brush, this.ClientRectangle);
            }
        }
    }
код управления пользователем
public partial class Progress : UserControl
    {
        public Progress()
        {
            InitializeComponent();
            lblMsg.Text = "";
            pbStatus.Minimum = 0;
            pbStatus.Maximum = 100;
        }

        public string Country { get; set; }
        public string DBConnection { get; set; }
        public string Sql { get; set; }

        public void SetMessage(string strMsg)
        {
            lblMsg.Text = strMsg;
        }

        public void Process()
        {
            var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
            Task.Factory.StartNew(() =>
            {
                lblMsg.BeginInvoke((MethodInvoker)delegate
                {
                    lblMsg.Text = "Connecting country " + Country;
                });

                pbStatus.BeginInvoke((MethodInvoker)delegate
                {
                    pbStatus.Value = 30;
                });
                System.Threading.Thread.SpinWait(50000000);

                //***********
                lblMsg.BeginInvoke((MethodInvoker)delegate
                {
                    lblMsg.Text = "executing sql for country " + Country;
                });

                pbStatus.BeginInvoke((MethodInvoker)delegate
                {
                    pbStatus.Value = 60;
                });
                System.Threading.Thread.SpinWait(50000000);

                //***********

                lblMsg.BeginInvoke((MethodInvoker)delegate
                {
                    lblMsg.Text = "sql executed successfully for country " + Country;
                });

                pbStatus.BeginInvoke((MethodInvoker)delegate
                {
                    pbStatus.Value = 100;
                });
                System.Threading.Thread.SpinWait(50000000);

            });
            //System.Threading.Thread.SpinWait(50000000); // do work here   
        }
    }

Ответы на вопрос(1)

Решение Вопроса

это может быть отправной точкой. Обработка паузы / резюме зависит от ваших потребностей и может быть изменена.

var cancellationTokenSource = new CancellationTokenSource();
var cancellation = cancellationTokenSource.Token;

void UpdateDatabases(IEnumerable<...> databases, CancellationToken cancellation)
{
   foreach(db in databases)
   {


   //create as many ProgressBar instances as databases you want to update
   //check if ProgressBar exist, then return it and reuse, otherwise create new
   ProgressBar pb = new ProgressBar();   
   pb.Maximum = iterations;   
   pb.Dock = DockStyle.Fill;   

   Controls.Add(pb);  



  //start thread for every database/progress bar

  Task.Factory.StartNew(progressBar => 
  {   
      var start = (ProgressBar)progressBar).Value; //use last value in case of pause
      Parallel.For(start, iterations, 
          new ParallelOptions(){CancellationToken =  cancellation}
      (i, loopState) =>  
      {   
          if (loopState.ShouldExitCurrentIteration)
                return;
          //perhaps check loopState.ShouldExitCurrentIteration inside worker method
          Thread.SpinWait(50000000); // do work here   

          BeginInvoke((Action)delegate { ((ProgressBar)progressBar).Value++; });   
      });   
   }, 
   pb, cancellation)

   .ContinueWith(task => 
  {
      //to handle exceptions use task.Exception member

      var progressBar = (ProgressBar)task.AsyncState;
      if (!task.IsCancelled)
      {
          //hide progress bar here and reset pb.Value = 0
      }
  }, 
  TaskScheduler.FromCurrentSynchronizationContext() //update UI from UI thread
  ); 

   }
}

 //.........

 //Call
 UpdateDatabases(databases, cancellation)  

 //To suspend, call 
 cancellationTokenSource.Cancel();

 //To resume - simply call UpdateDatabases  again
 cancellationTokenSource = new CancellationTokenSource();
 cancellation = cancellationTokenSource.Token;
 UpdateDatabases(databases, cancellation)  

UpdateI»

мы просмотрели ваш код Взгляните на пересмотренный код и адаптируйте его под свои нужды. Основные ошибки - связываться сclosures и создание Progress из не-пользовательского потока. Чтобы включить параллельную обработку, вы можете использовать Parallel.ForEach (возможные перегрузки смотрите в MSND). Также дизайн выглядит немного странно для менясмешивая данные и логику вProgress ). С точки зрения интерфейса этоТакже странно, что индикаторы выполнения отображаются в порядке обработки, а не в исходном порядке, как в списке (это будет проблемой, если вы решите отсортировать список по алфавиту)

Я надеюсь, что это поможет.

главное для кода

   private void btnStart_Click(object sender, EventArgs e)
    {
        Progress ucProgress = null;
        Dictionary<string, string=""> dicList = new Dictionary<string, string="">();
        dicList.Add("GB", "conn1");
        dicList.Add("US", "conn2");
        dicList.Add("DE", "conn3");
        fpPanel.Controls.Clear();

        Func<keyvaluepair<string, string="">, object> createProgress = entry =>
        {

            var tmp = new Progress {Country = entry.Key, DBConnection = entry.Value};
            fpPanel.Controls.Add(tmp);
            return tmp;
        };

        Task.Factory.StartNew(() =>
        {
            //foreach (KeyValuePair<string, string=""> entry in dicList)

            Parallel.ForEach(dicList,
                entry =>
                {

                    //create and add the Progress in UI thread
                    var ucProgress = (Progress)fpPanel.Invoke(createProgress, entry);

                    //execute ucProgress.Process(); in non-UI thread in parallel. 
                    //the .Process(); must update UI by using *Invoke
                    ucProgress.Process();

                    System.Threading.Thread.SpinWait(5000000);
                });
        });

    }
</string,></keyvaluepair<string,></string,></string,>

код управления пользователем

public void Process()
    {
        //uiScheduler - Not used
        //var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
        //The Task is not necessary because the Process() called from Parallel.ForEach 
        //Task.Factory.StartNew(() =>
        //{

            //BeginInvoke or Invoke required
            lblMsg.BeginInvoke((MethodInvoker)delegate
            {
                lblMsg.Text = "Connecting country " + Country;
            });

            pbStatus.BeginInvoke((MethodInvoker)delegate
            {
                pbStatus.Value = 30;
            });
            System.Threading.Thread.SpinWait(50000000);

            //***********
            lblMsg.BeginInvoke((MethodInvoker)delegate
            {
                lblMsg.Text = "executing sql for country " + Country;
            });

            pbStatus.BeginInvoke((MethodInvoker)delegate
            {
                pbStatus.Value = 60;
            });
            System.Threading.Thread.SpinWait(50000000);

            //***********

            lblMsg.BeginInvoke((MethodInvoker)delegate
            {
                lblMsg.Text = "sql executed successfully for country " + Country;
            });

            pbStatus.BeginInvoke((MethodInvoker)delegate
            {
                pbStatus.Value = 100;
            });
            System.Threading.Thread.SpinWait(50000000);

        //});
        //System.Threading.Thread.SpinWait(50000000); // do work here   
    }
 Thomas05 июн. 2013 г., 16:42
Я думаю, вы не проверили ваш код на ошибку компиляции. я просто копирую, вставляю твой код и получаю ошибку. если возможно, пожалуйста, запустите код в конце ур, а затем вы можете увидеть детали ошибки компиляции. пожалуйста, исправьте это, если это возможно. Спасибо
 Vlad I.05 июн. 2013 г., 12:37
Task.Create () - этот метод не существует в .NET 4 System.Threading.Tasks.Task. Я скопировал часть вашего кода с ошибкой :) (обновлено). "Как уведомить, когда каждая задача выполнена? - когда задача будет выполнена, будет выполнена часть ContinueWith (в потоке пользовательского интерфейса, чтобы вы могли безопасно обновлять элементы управления пользовательского интерфейса). В ContinueWith делегата вы можете обрабатывать завершение задачи и причину, по которой задача завершена. Какая задача выполнена, передается в параметре делегата ContinueWith.
 Vlad I.05 июн. 2013 г., 10:15
@ Томас Я обновил образец. Я имел в виду метод, который оборачиваетforeach -.UpdateDatabases()
 Vlad I.05 июн. 2013 г., 16:53
@ Томас, это фрагмент кода (starting point), образец и не может рассматриваться как окончательное, готовое к использованию решение, поэтому вы не можете просто скопировать / вставить Поэтому, пожалуйста, попробуйте скомпилировать и настроить свой реальный проект. Возможно ошибка компиляции в строкеvoid UpdateDatabases(IEnumerable databases, Пожалуйста, посмотрите на комментарии в коде тоже.

Ваш ответ на вопрос