对于数据量较小的情况,使用串行处理的方法(ProcessSheetOriginal)可能更有效率,因为:
- 较少的开销:串行处理避免了线程管理和同步的开销。创建和管理线程需要一定的系统资源,对于数据量不大的任务,这些开销可能会抵消并行处理带来的性能提升。
- 数据传输和 IO:处理较小的数据集时,数据的读取和写入操作可能会占据大部分时间。串行处理方法直接在内存中操作数据,减少了对工作表的频繁读取和写入,从而可能提高效率。
- 线程调度:操作系统在并行处理中需要调度多个线程,这可能会引入上下文切换的开销。如果数据量不大,并行处理的调度开销可能会超过实际的处理时间,导致整体性能降低。
小数据集中的串行处理优势
- 简洁性:串行处理代码通常更简洁,逻辑更易于理解和维护。
- 性能:对于小规模的数据处理,串行代码往往能够提供足够的性能,因为操作系统的线程管理开销在这种情况下可能会超过并行处理带来的性能改进。
大数据集中的并行处理优势
- 并行计算:当数据量大到足够影响处理时间时,并行处理能够将工作分解到多个处理器核心上,加快整体处理速度。
- 提升效率:对于数据量非常大的任务,并行处理能够显著提高处理效率,特别是在处理复杂计算和大量数据时。
代码示例
0. 引入命名空间
Imports System.Windows.Forms
Imports System.Data
Imports Microsoft.Data.SqlClient
Imports Microsoft.Office.Interop.Excel
1. excel处理方法
串行处理代码:
' 花费时间 00:00:00.0375333 (IsRunning = False)
Public Shared Sub ProcessSheetOriginal(sheet As Worksheet)
Dim stopwatch As New Stopwatch()
stopwatch.Start()
Dim usedRange As Range = sheet.UsedRange
Dim values As Object(,) = usedRange.Value2
Dim rows As Integer = values.GetLength(0)
Dim cols As Integer = values.GetLength(1)
For i As Integer = 1 To rows
For j As Integer = 1 To cols
If values(i, j) IsNot Nothing AndAlso TypeOf values(i, j) Is String Then
Dim originalValue As String = values(i, j).ToString()
Dim convertedValue As String = ConvertFullWidthAndHalfWidth(originalValue)
' 只有在值发生变化时才进行赋值
If Not originalValue.Equals(convertedValue) Then
values(i, j) = convertedValue
End If
End If
Next
Next
usedRange.Value2 = values
stopwatch.Stop()
Console.WriteLine($"ProcessSheetOriginal 执行时间: {stopwatch.ElapsedMilliseconds} ms")
End Sub
并行处理代码:
' 花费时间 00:00:00.0588076 (IsRunning = False)
Public Shared Sub ProcessSheetParallel(sheet As Worksheet)
Dim stopwatch As New Stopwatch()
stopwatch.Start()
Dim usedRange As Range = sheet.UsedRange
Dim values As Object(,) = usedRange.Value2
Dim rows As Integer = values.GetLength(0)
Dim cols As Integer = values.GetLength(1)
' 使用 Parallel.For 实现并行处理
Parallel.For(1, rows + 1, Sub(i)
For j As Integer = 1 To cols
If values(i, j) IsNot Nothing AndAlso TypeOf values(i, j) Is String Then
Dim originalValue As String = values(i, j).ToString()
Dim convertedValue As String = ConvertFullWidthAndHalfWidth(originalValue)
' 只有在值发生变化时才进行赋值
If Not originalValue.Equals(convertedValue) Then
values(i, j) = convertedValue
End If
End If
Next
End Sub)
usedRange.Value2 = values
stopwatch.Stop()
Console.WriteLine($"ProcessSheetParallel 执行时间: {stopwatch.ElapsedMilliseconds} ms")
End Sub
2. 实际修改方法
Shared Function ConvertFullWidthAndHalfWidth(text As String) As String
' 替换全角空格为半角空格
text = text.Replace(ChrW(12288), ChrW(32)) ' 全角空格 (U+3000) 转为 半角空格 (U+0020)
' 转换全角英文字符为半角英文字符,并将假名字符转换为全角
Dim sb As New System.Text.StringBuilder()
For Each c As Char In text
Dim code As Integer = AscW(c)
If code >= 65281 AndAlso code <= 65374 Then
' 全角字符转为半角字符
sb.Append(ChrW(code - 65248))
ElseIf code >= 65382 AndAlso code <= 65439 Then
' 半角假名字符转为全角假名字符
sb.Append(ChrW(code + 65248))
Else
sb.Append(c)
End If
Next
Return sb.ToString()
End Function
3. 案例全部代码
Imports Excel = Microsoft.Office.Interop.Excel
Imports System.Diagnostics
Imports System.Threading.Tasks
Public Class ExcelProcessor
' 假设这些方法已经定义在你的类中
Public Shared Sub ProcessSheetOriginal(sheet As Excel.Worksheet)
Dim stopwatch As New Stopwatch()
stopwatch.Start()
Dim usedRange As Excel.Range = sheet.UsedRange
Dim values As Object(,) = usedRange.Value2
Dim rows As Integer = values.GetLength(0)
Dim cols As Integer = values.GetLength(1)
For i As Integer = 1 To rows
For j As Integer = 1 To cols
If values(i, j) IsNot Nothing AndAlso TypeOf values(i, j) Is String Then
Dim originalValue As String = values(i, j).ToString()
Dim convertedValue As String = ConvertFullWidthAndHalfWidth(originalValue)
' 只有在值发生变化时才进行赋值
If Not originalValue.Equals(convertedValue) Then
values(i, j) = convertedValue
End If
End If
Next
Next
usedRange.Value2 = values
stopwatch.Stop()
Console.WriteLine($"ProcessSheetOriginal 执行时间: {stopwatch.ElapsedMilliseconds} ms")
End Sub
Public Shared Sub ProcessSheetParallel(sheet As Excel.Worksheet)
Dim stopwatch As New Stopwatch()
stopwatch.Start()
Dim usedRange As Excel.Range = sheet.UsedRange
Dim values As Object(,) = usedRange.Value2
Dim rows As Integer = values.GetLength(0)
Dim cols As Integer = values.GetLength(1)
' 使用 Parallel.For 实现并行处理
Parallel.For(1, rows + 1, Sub(i)
For j As Integer = 1 To cols
If values(i, j) IsNot Nothing AndAlso TypeOf values(i, j) Is String Then
Dim originalValue As String = values(i, j).ToString()
Dim convertedValue As String = ConvertFullWidthAndHalfWidth(originalValue)
' 只有在值发生变化时才进行赋值
If Not originalValue.Equals(convertedValue) Then
values(i, j) = convertedValue
End If
End If
Next
End Sub)
usedRange.Value2 = values
stopwatch.Stop()
Console.WriteLine($"ProcessSheetParallel 执行时间: {stopwatch.ElapsedMilliseconds} ms")
End Sub
Public Shared Function ConvertFullWidthAndHalfWidth(text As String) As String
' 替换全角空格为半角空格
text = text.Replace(ChrW(12288), ChrW(32)) ' 全角空格 (U+3000) 转为 半角空格 (U+0020)
' 转换全角英文字符为半角英文字符
Dim sb As New System.Text.StringBuilder()
For Each c As Char In text
Dim code As Integer = AscW(c)
If code >= 65281 AndAlso code <= 65374 Then
' 全角字符转为半角字符
sb.Append(ChrW(code - 65248))
Else
sb.Append(c)
End If
Next
Return sb.ToString()
End Function
Public Sub TestMethods()
' 创建 Excel 应用程序实例
Dim excelApp As New Excel.Application()
Dim workbook As Excel.Workbook = excelApp.Workbooks.Open("C:\Path\To\Your\Workbook.xlsx")
Dim sheet As Excel.Worksheet = workbook.Sheets(1) ' 获取第一个工作表
' 测试串行处理
Console.WriteLine("Testing ProcessSheetOriginal...")
ProcessSheetOriginal(sheet)
' 测试并行处理
Console.WriteLine("Testing ProcessSheetParallel...")
ProcessSheetParallel(sheet)
' 清理和保存工作簿
workbook.Save()
workbook.Close()
excelApp.Quit()
' 释放 COM 对象
ReleaseObject(sheet)
ReleaseObject(workbook)
ReleaseObject(excelApp)
End Sub
Private Sub ReleaseObject(ByVal obj As Object)
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
obj = Nothing
Catch ex As Exception
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
End Class
说明
ConvertFullWidthAndHalfWidth: 用于全角和半角字符转换的辅助方法。ProcessSheetOriginal: 串行处理工作表数据的方法。ProcessSheetParallel: 并行处理工作表数据的方法。TestMethods: 测试方法,创建 Excel 应用程序实例,打开指定的工作簿,调用串行和并行处理方法,并保存和关闭工作簿。ReleaseObject: 用于释放 COM 对象的辅助方法,确保在使用完 Excel 对象后进行正确的清理。
运行测试
- 你需要将
"C:\Path\To\Your\Workbook.xlsx"替换为你实际的 Excel 文件路径。 - 确保你的 Excel 环境配置正确,并且已经引用了必要的 Excel Interop 库。
这段代码将测试并比较串行处理和并行处理在实际数据上的执行时间。