VB.Net 在并行 ForEach 中使用 XmlNodeList

VB.Net Use XmlNodeList in a parallel ForEach

我有一段代码遍历 XmlNodeList 中的节点,并根据节点名称为每个节点创建不同的对象,并将其添加到列表中进行打印。

For Each node as XmlNode In nodeList
    Select Case node.Name.ToUpper()
        Case "SHAPE"
            _items.Add(New ShapeTemplate(node, Me))
        Case "TEXTBLOCK"
            _items.Add(New TextblockTemplate(node, Me))
    End Select
Next

此代码工作正常,但由于必须由 ShapeTemplate 和 TextblockTemplate 构造函数完成的所有工作,它非常慢。由于将订单对象添加到 _items 无关紧要,我认为加快速度的一个好方法是使用 parallel.ForEach 循环。问题是 XmlNodeList 不能与 parallel.ForEach 一起使用,因为它是一个非通用集合。我一直在研究将 XmlNodeList 转换为 List(Of XmlNode) 的方法,但没有成功。我经常看到的答案是

Dim nodes as New List(Of xmlNode)(nodeList.Cast(Of xmlNode)())

但是当我尝试时,我收到一条错误消息,告诉我 'Cast' 不是 XmlNodeList 的成员。

我也试过像这样使用 TryCast

Dim nodes as List(Of XmlNode) = TryCast(CObj(nodeList), List(Of XmlNode))

但它导致节点为 Nothing,因为无法投射对象。

有人知道如何在 parallel.ForEach 循环中使用 XmlNodeList 吗?

编辑:我尽量避免使用循环进行转换

正如所见 hereXmlNodeList 可以通过 OfType.

传递给构造函数来转换为泛型 List(Of XmlNode)
' I added so your code could compile.
' I assumed an interface shared by ShapeTemplate and TextblockTemplate
Dim nodeList As XmlNodeList
Dim _items As New List(Of ITemplate)

Dim _nodes As New List(Of XmlNode)(nodeList.OfType(Of XmlNode))

现在并行循环。请注意,如果要添加到非线程安全集合(例如 List),则需要同步将对象添加到列表中。所以我将耗时部分(模板构造函数)与快速操作(添加到列表)分开。这应该会提高您的表现。

Dim oLock As New Object
Parallel.ForEach(
    _nodes,
    Sub(node)
        Dim item As ITemplate
        Select Case node.Name.ToUpper()
            Case "SHAPE"
                item = New ShapeTemplate(node, Me)
            Case "TEXTBLOCK"
                item = New TextblockTemplate(node, Me)
            Case Else
                item = Nothing ' or, do something else?
        End Select
        SyncLock oLock
            _items.Add(item)
        End SyncLock
    End Sub)

您可以使用 Parallel LINQ 而不是 Parallel.ForEach,这似乎更适合这种转换。这看起来就像一个普通的 LINQ 查询,但添加了 .AsParallel()

Imports System.Linq

' _items will not be in same order as nodes in nodeList.
' Add .AsOrdered() after .AsParallel() to maintain order, if needed.
_items = (
    From node In nodeList.Cast(Of XmlNode)().AsParallel()
    Select item = CreateTemplate(node)
    Where item IsNot Nothing
).ToList()

Function CreateTemplate(node As XmlNode) As ITemplate ' interface or base class for your types
    Dim item As ITemplate
    Select Case node.Name.ToUpper()
        Case "SHAPE"
            item = New ShapeTemplate(node, Me)
        Case "TEXTBLOCK"
            item = New TextblockTemplate(node, Me)
        Case Else
            item = Nothing
    End Select
    Return item
End Function