【问题标题】:How to use Parallel.ForEach to loop into a DataGridViewRow如何使用 Parallel.ForEach 循环进入 DataGridViewRow
【发布时间】:2019-04-04 03:22:12
【问题描述】:

我在下面有一个代码循环遍历包含服务器和服务名称的 datagridview 中的每一行,并使用 ServiceController 引用检查每个服务的状态并返回单元格上的值。

        For Each dgvrow As DataGridViewRow In DataGridView1.Rows
        myController = New ServiceController With {
        .MachineName = dgvrow.Cells(0).Value,
        .ServiceName = dgvrow.Cells(1).Value
        }
        dgvrow.Cells(2).Value = myController.Status.ToString
        Next

这可行,但它是按顺序运行的,每个线程在进入下一行之前需要时间来完成,所以我想并行运行它。

我在这里搜索并偶然发现了 Parallel.ForEach,但我找不到正确的代码/组合来完成这项工作。

我最初的尝试是

Parallel.ForEach(dgvrow as DataGridViewRow in DatagridView1.Rows
Sub(myServer)
    myController = New ServiceController With {
        .MachineName = dgvrow.Cells(0).Value,
        .ServiceName = dgvrow.Cells(1).Value
        }
        dgvrow.Cells(2).Value = myController.Status.ToString
End Sub
)

这绝对是错误的,不知道在 ForEach 部分后面放什么

预期结果应如下所示,我希望服务状态列同时填满。

<table border=1>
  <tr>
    <th>Server Name</th>
    <th>Service Name</th> 
    <th>Service Status</th>
  </tr>
  <tr>
    <th>Server 1</th>
    <th>Service 1</th> 
    <th>Not Running</th>
  </tr>
  <tr>
    <th>Server 2</th>
    <th>Service 2</th> 
    <th>Running</th>
  </tr>
  <tr>
    <th>Server 3</th>
    <th>Service 3</th> 
    <th>Not Running</th>
  </tr>
  </table>

【问题讨论】:

  • A DataGridView 是一个 UI 元素 - 您不能从 UI 以外的任何线程访问它。你不能在上面使用Parallel.ForEach。你想计算什么让你想要并行计算?
  • 您是否正在尝试实时更新状态?
  • 最终,是的。我正在尝试弄清楚如何并行获取状态,因为这将在 20 多台服务器的列表上运行,并且需要一些时间来检查每台服务器而不进行并行处理。
  • 这听起来像是 Microsoft 的反应式框架 (Rx) 更好的工作。

标签: vb.net parallel.foreach


【解决方案1】:

DataGridView 是一个 UI 元素 - 您不能从 UI 以外的任何线程访问它。你不能在上面使用Parallel.ForEach

您可以将数据提取为非 UI 对象,并行处理,然后将结果分配回去。

试试这个:

'UI thread
Dim inputs = DataGridView1.Rows.Cast(Of DataGridViewRow).Select(Function(dgvrow) New With _
{
    .MachineName = dgvrow.Cells(0).Value,
    .ServiceName = dgvrow.Cells(1).Value
}).ToArray()

'Parallel
Dim serviceControllers = inputs.AsParallel().Select(Function (x) New ServiceController With _
{
    .MachineName = x.MachineName,
    .ServiceName = x.ServiceName
}).ToArray()

'UI thread
For Each x In serviceControllers.Zip(DataGridView1.Rows.Cast(Of DataGridViewRow), Function (sc, dgvrow) New With { sc, dgvrow })
    x.dgvrow.Cells(2).Value = x.sc.Status.ToString
Next

如果在计算过程中行更改顺序,请使用此选项。

'UI thread
Dim inputs = DataGridView1.Rows.Cast(Of DataGridViewRow).Select(Function(dgvrow) New With _
{
    .MachineName = dgvrow.Cells(0).Value,
    .ServiceName = dgvrow.Cells(1).Value,
    .dgvrow = dgvrow
}).ToArray()

'Parallel
Dim results = inputs.AsParallel().Select(Function (x) New With
{
    .sc = New ServiceController With _
    {
        .MachineName = x.MachineName,
        .ServiceName = x.ServiceName
    }, _
    .dgvrow = x.dgvrow
}).ToArray()

'UI thread
For Each x In results
    x.dgvrow.Cells(2).Value = x.sc.Status.ToString
Next

请记住,如果在计算过程中删除了行,这也会失败。


您应该使用 Microsoft 的反应式框架(又名 Rx)- NuGet System.Reactive.Windows.Forms 并添加 using System.Reactive.Linq; - 然后您可以这样做:

'UI thread
Dim inputs = DataGridView1.Rows.Cast(Of DataGridViewRow).Select(Function(dgvrow) New With _
{
    .MachineName = CType(dgvrow.Cells(0).Value, String),
    .ServiceName = CType(dgvrow.Cells(1).Value, String),
    .Row = dgvrow
}).ToArray()

'Rx query
Dim query = _
    From x In inputs.ToObservable()
    From s In Observable.Start(Function () FetchStatus(x.MachineName, x.ServiceName))
    Select New With
    {
        x.Row,
        .Status = s
    }

'Rx subscription
Dim subscription As IDisposable = _
    query _
        .ObserveOn(DataGridView1) _
        .Subscribe(Sub (x) x.Row.Cells(2).Value = x.Status)

这将在响应返回后尽快更新每一行 - 并将并行处理。

我假设你有一个带有这个签名的函数:Function FetchStatus(MachineName As String, ServiceName As String) As String

【讨论】:

  • 这似乎有效,但最后一部分是否仍然显示正确行的正确状态?当我尝试使用包含 10 行(服务器)的列表运行代码时,我仍然会从上到下依次填充 dgvrow.Cells(2).Value。我希望每 10 行上的所有 Cell(2) 都能同时获得一个值。
  • @Ruben_PH - 只要在计算过程中行的顺序没有改变。
  • @Ruben_PH - 如果对行更改顺序有任何疑问,那么只需通过计算将实际行向下传递到匿名对象中。
  • 有没有办法让 Cell(2) 同时填充?在大约 10 个服务器的列表上运行它,我看到 Cell(2) 仍然从上到下填充。
  • 我添加了一些关于预期结果的问题的更多细节
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-05
  • 1970-01-01
相关资源
最近更新 更多