Создание строк в сетке данных с использованием Parallel.ForEach - PullRequest
0 голосов
/ 05 декабря 2011

Недавно решил написать «быстрое» приложение для создания формы Windows, чтобы пометить мои MP3-файлы.Со времени .Net 3.0 ничего не сделано с параллелизмом, поэтому я смотрю на метод Parallel.ForEach, чтобы справиться с блокировкой пользовательского интерфейса, которую я получаю, когда использую стандартный оператор foreach.Вот выдержка:

var i = 1;
var files = new List<string>(); // File list is populated using recursive method.

foreach(var f in files) {
    // Add a row
    var row = dgvList.Rows[dgvList.Rows.Add()];

    // Update label
    lblSummary.Text = string.Concat("Processing... ", i);
    // Do things with row

    // Increment progress bar
    progressBar.PerformStep();
    i++;
}

Я понял простое использование Parallel.ForEach (), но я не уверен, что должен использовать этот конкретный метод для обновления пользовательского интерфейса?Есть предложения?

Ответы [ 3 ]

0 голосов
/ 05 декабря 2011

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

Что вам нужно сделать, это переместить бизнес-логику в фоновые задачи и обновить пользовательский интерфейс с помощью диспетчера, который будетвыполнить его в потоке пользовательского интерфейса

, так как MSDN говорит

It is important to keep your application's user interface (UI) responsive. If an 
operation contains enough work to warrant parallelization, then it likely should not
be run that operation on the UI thread. Instead, it should offload that operation to 
be run on a background thread. For example, if you want to use a parallel loop to 
compute some data that should then be rendered into a UI control, you should consider
executing the loop within a task instance rather than directly in a UI event handler. 
Only when the core computation has completed should you then marshal the UI update back 
to the UI thread.

и, что особенно важно, если вы пытаетесь обновить поток пользовательского интерфейса из Paralle.Foreach

If you do run parallel loops on the UI thread, be careful to avoid updating UI 
controls from within the loop. Attempting to update UI controls from within a parallel 
loop that is executing on the UI thread can lead to state corruption, exceptions, 
delayed updates, and even deadlocks, depending on how the UI update is invoked
0 голосов
/ 09 декабря 2011

ОК, я нашел лучший способ добиться этого, запустив что-то вроде этого:

// Kick off thread
Task.Factory.StartNew(delegate{
     foreach(var x in files) {
         // Do stuff

         // Update calling thread's UI
         Invoke((Action)(() => {
              progressBar.PerformStep();
         }));
     }
}

Я на самом деле обновил свой код, чтобы заполнить список в цикле foreach, а затем назначил его для daragrid через .DataSource вместо непосредственной работы с коллекцией .Rows. Должен был сделать это с самого начала действительно:)

0 голосов
/ 05 декабря 2011

Вы должны быть очень осторожны с безопасностью потока.Вы должны обязательно заблокировать любой используемый вами объект и разблокировать его соответствующим образом.

В противном случае не должно быть никаких проблем с использованием Parallel.ForEach для пользовательского интерфейса.

РЕДАКТИРОВАТЬ: выможно установить Form.CheckForIllegalCrossThreadCalls = false, чтобы отключить проверку безопасности потока.Вот некоторая документация: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.checkforillegalcrossthreadcalls.aspx
Это будет работать, но это опасно, потому что тогда вам нужно самим заботиться о безопасности потоков.

Лучший способ справиться с этим - использовать шаблон invoke для UI-логики, но тогда пострадает параллелизм, поскольку сама операция UI будет вызываться в потоке UI.Это, однако, безопасный способ сделать что-то.Документация: http://msdn.microsoft.com/en-us/library/ms171728.aspx

...