每次读取Excel工作表时使用并行foreach的不同结果

时间:2014-03-16 15:14:41

标签: vb.net excel task-parallel-library excel-interop parallel.foreach

Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Collections.Concurrent
Imports Excel = Microsoft.Office.Interop.Excel

Public Class TestCarDatas
    Public Property RowID As Integer
    Public Property ModelYear As Integer
    Public Property VehMfcName As String
    Public Property EmgVeh As Boolean
End Class

Module ExcelParallelDataGather2
    Public Const ExcelVehDataPath As String = "D:\Users\Dell\Desktop"
    Public rwl As New System.Threading.ReaderWriterLock()
    Public rwl_writes As Integer = 0
    Public FullTestVehData As New List(Of TestCarDatas)()
    Public x1App As New Excel.Application
    Public x1Workbook As Excel.Workbook
    Public x1Worksheet1 As Excel.Worksheet
    Public x1WkshtLrow As Integer

    Sub main()
        x1App.Visible = False
        ErrorNotify = False
        Console.WriteLine("Excel Parallel foreach operation program....")
        Dim cki As ConsoleKeyInfo
        x1Workbook = x1App.Workbooks.Open(Path.Combine(ExcelVehDataPath, "TestCarDatabase2014.xls"), , True)
        x1Worksheet1 = x1Workbook.Sheets(1)
        Do
            Console.WriteLine("Press escape key to exit, 'a' key to reiterate, 'c' key to clear console")
            cki = Console.ReadKey()
            If Chr(cki.Key).ToString = "A" Then
                Console.WriteLine("--> Processing...")
                FullTestVehData.Clear()
                rwl_writes = 0
                Parallel.ForEach(Partitioner.Create(11, x1WkshtLrow + 1), _
                Function()
                    ' Initialize the local states 
                    Return New List(Of TestCarDatas)()
                End Function, _
                Function(partrange, loopState, localState)
                    ' Accumulate the thread-local computations in the loop body
                    localState = populateCardata(x1Worksheet1, partrange.Item1, partrange.Item2)
                    Return (localState)
                End Function, _
                Sub(finalstate)
                    ' Combine all local states
                    Try
                        rwl.AcquireWriterLock(Timeout.Infinite)
                        Try
                            ' It is safe for this thread to read or write
                            ' from the shared resource in this block
                            FullTestVehData.AddRange(finalstate)
                            Interlocked.Increment(rwl_writes)
                        Finally
                            ' Ensure that the lock is released.
                            rwl.ReleaseWriterLock()
                        End Try
                    Catch ex As ApplicationException
                        ' The writer lock request timed out.
                    End Try
                End Sub)
            End If
            If Chr(cki.Key).ToString = "C" Then
                Console.Clear()
                Console.WriteLine("Excel Parallel foreach operation program....")
            End If
            If Chr(cki.Key).ToString <> "A" And Chr(cki.Key).ToString <> "C" And _
               cki.Key <> ConsoleKey.Escape Then
                Console.WriteLine("")
                Console.WriteLine("Invalid response via key press")
            End If
        Loop While (cki.Key <> ConsoleKey.Escape)
    End Sub

    Friend Function populateCardata(ByVal WksheetObj As Excel.Worksheet, ByVal rngStart As Integer, _
                                    ByVal rngStop As Integer) As List(Of TestCarDatas)
        Dim wkrng(12) As String
        Dim PartVehData As New List(Of TestCarDatas)
        PartVehData.Clear()
        For i As Integer = rngStart To rngStop - 1
            Dim data As New TestCarDatas
            For j As Integer = 0 To 12
                wkrng(j) = WksheetObj.Cells(i, j + 1).Address(RowAbsolute:=False, ColumnAbsolute:=False)
            Next
            With data
                .RowID = i
                .ModelYear = WksheetObj.Range(wkrng(0)).Value2
                .VehMfcName = WksheetObj.Range(wkrng(1)).Value2
                If WksheetObj.Range(wkrng(11)).Value2 = "Y" Then
                    .EmgVeh = True
                Else
                    .EmgVeh = False
                End If
            End With
            PartVehData.Add(data)
        Next
        Return PartVehData
    End Function

End Module


我试图使用并行foreach和range Partitioner获取Excel工作表数据,在线程本地存储中创建列表,最后使用synclock或reader-writer锁等线程安全方法添加它们

工作表中从11行到最后一行的行将被读取并填充在列表中(T)
当我执行上面的代码

时,我会观察到以下情况
  1. 当工作表中的行更大时(示例&gt; 2000),此代码每次都按预期工作
  2. 当工作表中的行较少时,此代码在前几次迭代期间返回部分列表(某些分区范围的数据丢失)。如果我重复它(按键&#39; a&#39;)多次,那么有时它会返回预期的结果(最终列表计数=需要读取的excel行的数量)

  3. 为什么会出现这种现象?
    使用并行foreach的解决方案是什么,如果我在第一次运行/迭代期间需要正确的结果,而不管是否。工作表中的行数?

0 个答案:

没有答案