Как использовать DataGridView параллельно.Для?

#vb.net #parallel-processing

Вопрос:

Это часть моей программы:

 Parallel.For(1, m,
            Sub(i)
                
  ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

 Dim html As String = ""

 Dim request As HttpWebRequest = HttpWebRequest.Create(slink(i, 1))

 request.AutomaticDecompression = DecompressionMethods.GZip

 request.Timeout = 500

 request.Method = "GET"

  request.UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0"

 Using response As Task(Of WebResponse) = request.GetResponseAsync

 If response.Result IsNot Nothing Then

  Using ioStream As IO.Stream = response.Result.GetResponseStream

 Using sr As New System.IO.StreamReader(ioStream)

                                    html = sr.ReadToEnd

                                    s = html.Split(";")
         
                                    r = s(0).Split(",")

  row = New String() {r(0),r(1),r(2),r(3),r(4),r(5)}

 DataGridView1.Rows.Add(row)
                                        DataGridView1.FirstDisplayedScrollingRowIndex = DataGridView1.RowCount - 1

                           End Using

                            End Using

                        End If

                    End Using
              
            End Sub)
 

Когда я запускаю программу, возникает следующая ошибка. Как я могу это исправить?

Исключение типа » Система.Исключение InvalidOperationException» произошло в системе.Windows.Формы.dll, но не был обработан в пользовательском коде

Дополнительная информация: Недопустимая операция с перекрестным потоком: Управление «dataGridView1», доступ к которому осуществляется из потока, отличного от потока, в котором он был создан.

Комментарии:

1. Думаю, вы, возможно,захотите немного переосмыслить свою стратегию. Вместо того, чтобы обновлять представление DataGrid в потоках, вам, вероятно, будет лучше написать в резервный источник данных для этого представления DataGrid, а затем, возможно, выполнить однократное обновление DVG после вашей параллели.для

2. Проблема должна быть довольно очевидной. Параллельные операции выполняются в фоновых потоках, и только поток пользовательского интерфейса может получить доступ к пользовательскому интерфейсу, который включает вашу сетку. Сначала вам нужно будет перенести данные из сетки в какую-либо другую структуру данных, обработать их параллельно, а затем обновить сетку. Если у вас есть DataTable привязка к сетке, даже обработка этого непосредственно в фоновом режиме вызовет проблему, потому что любые изменения будут отражены в сетке, и это вызовет исключение перекрестного потока. Короче говоря, все, что влияет на пользовательский интерфейс, ДОЛЖНО выполняться только в потоке пользовательского интерфейса.

3. @Hursey Спасибо за ваш комментарий. Только полное время выполнения параллели занимает 45 секунд. Если мы используем DGV после параллели, то через 45 секунд информация будет отображаться в самом DVG , но если DVG можно разместить внутри параллели, любой проверяемый URL-адрес будет содержать свою информацию в DVG, и мы не будем тратить время.

4. @jmcilhinney Спасибо за ваш комментарий. В моей программе мы берем информацию с нескольких сайтов одновременно, и я хочу одновременно показывать эту информацию в DVG. Возможно ли это?

5. Конечно, это возможно, но вы не можете коснуться сетки в фоновом потоке. Вы можете собрать данные из любого количества источников и упаковать их в фоновом потоке, но затем вы должны загрузить их в сетку в потоке пользовательского интерфейса. Исходя из того, что вы делаете, у вас есть два основных выбора. Вы можете либо запустить параллельные задачи и сначала загрузить данные в структуру данных (например, a), а затем загрузить их в сетку, либо вы можете выполнить вызов потока пользовательского интерфейса из параллельных задач для обновления сетки в потоке пользовательского интерфейса. DataTable Если можно обновить сетку в конце, сделайте первое.

Ответ №1:

Самым простым вариантом было бы заменить эти строки:

 DataGridView1.Rows.Add(row)
DataGridView1.FirstDisplayedScrollingRowIndex = DataGridView1.RowCount - 1
 

с этим:

 DataGridView1.BeginInvoke(Sub()
                              DataGridView1.Rows.Add(row)
                              DataGridView1.FirstDisplayedScrollingRowIndex = DataGridView1.RowCount - 1
                          End Sub)
 

Чтобы узнать больше о том, как это работает и как использовать последовательный пошаговый процесс для маршалирования вызова потока пользовательского интерфейса, см. Здесь.