Шаблон WinForms TPL с несколькими задачами и синхронизацией пользовательского интерфейса - это правильно? - PullRequest
2 голосов
/ 20 июля 2011

Я новичок в TPL (Task-Parallel Library) и мне интересно, является ли следующий способ наиболее эффективным способом ускорения 1 или более задач, сопоставления результатов и отображения их в сетке данных.

  1. Search1 & Search2 взаимодействуют с двумя отдельными базами данных, но возвращают одинаковые результаты.
  2. Я отключаю кнопки и включаю счетчик.
  3. Я запускаю задачи с помощью одного вызова метода ContinueWhenAll.
  4. Я добавил планировщик в вызов ContinueWhenAll для обновления кнопок формы, сетки данных и отключения счетчика.

В: Я делаю это правильно? Есть ли лучший способ?
В: Как я могу добавить отмену / проверку исключений к этому?
В: Если бы мне нужно было добавить отчеты о проделанной работе - как бы я это сделал?

Причина, по которой я выбрал этот метод, скажем, фоновый, заключается в том, что я мог запускать каждую задачу БД параллельно или последовательно. Кроме того, я подумал, что было бы забавно использовать TPL ... однако, поскольку я не смог найти никаких конкретных примеров того, что я делаю ниже (несколько задач), я подумал, что было бы неплохо поставить его здесь, чтобы получить ответы, и, надеюсь, быть примером для других.

Спасибо!

Код:

//  Disable buttons and start the spinner
btnSearch.Enabled = btnClear.Enabled = false;
searchSpinner.Active = searchSpinner.Visible = true;

//  Setup scheduler
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();

//  Start the tasks
Task.Factory.ContinueWhenAll(
  //  Define the search tasks that return List<ImageDocument>
  new [] {  
    Task.Factory.StartNew<List<ImageDocument>>(Search1), 
    Task.Factory.StartNew<List<ImageDocument>>(Search2) 
  }, 
  //  Process the return results
  (taskResults) => {
    //  Create a holding list
    List<ImageDocument> documents = new List<ImageDocument>();
    //  Iterate through the results and add them to the holding list
    foreach (var item in taskResults) {
      documents.AddRange(item.Result);
    }
    //  Assign the document list to the grid
    grid.DataSource = documents;
    //  Re-enable the search buttons
    btnSearch.Enabled = btnClear.Enabled = true;
    //  End the spinner
    searchSpinner.Active = searchSpinner.Visible = false;
  }, 
  CancellationToken.None, 
  TaskContinuationOptions.None, 
  scheduler
);

Ответы [ 2 ]

2 голосов
/ 20 июля 2011

В: Я делаю это правильно?Есть ли лучший способ?

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

В: Как я могу добавить проверку отмены / исключения к этому?

Вы можете передать CancellationToken вашим методам и заставить их проверить его и выдать, если запрашивается отмена.

Вы обработаете исключения, гдеВы получаете результаты из TaskResults.Эта строка:

  documents.AddRange(item.Result);

Где будет выброшено исключение (как AggregateException или OperationCanceledException), если во время операций возникло исключение или отмена.

Q: Если бы мне нужно было добавить отчеты о прогрессе - как бы я это сделал?

Самый простой способ - передать планировщик в ваши методы.Как только вы это сделаете, вы можете использовать его для планирования задачи, которая обновляется в потоке пользовательского интерфейса - то есть: Task.Factory.StartNew с указанным TaskScheduler.


однако, так как яне могу найти никаких конкретных примеров того, что я делаю ниже (несколько задач)

Просто к вашему сведению - у меня есть примеров работы с несколькими задачами в части 18 моего серия по TPL .

0 голосов
/ 20 июля 2011

Для получения наилучших рекомендаций прочитайте документ Асинхронный шаблон на основе задач .В него включены рекомендации по поддержке отмены и уведомлению о ходе выполнения для API на основе Task.

Вам также будут полезны ключевые слова async / await в Async CTP;они значительно упрощают продолжение задач.

...