#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)
Чтобы узнать больше о том, как это работает и как использовать последовательный пошаговый процесс для маршалирования вызова потока пользовательского интерфейса, см. Здесь.