总结任务中返回的小数

Summing up decimals returned within task

我正在尝试 运行 通过 1-X 项的列表并在任务中处理它们以加快处理的完成速度(它们发出的网络请求有时可能需要很短的时间才能完成).我正在尝试对处理完成时返回的小数求和,而不是再次循环遍历列表。就像现在一样,总和被每个任务覆盖而不是添加到。

我可以在将小数加到总和之前插入一个短暂的停顿,这似乎工作正常,但我确信那里有更好的解决方案。

我看到有人提到过 SyncLock,但我不能在 Decimal 上使用它。

这是我写的一些测试代码。 .Process 方法只是等待一个随机的秒数并将 .Value 属性 设置为一个随机小数。

有什么改进和正确计算总和的建议吗?

    Try
        Dim lstItem As List(Of clsItem) = GetList()
        Dim lstViewItem As New List(Of ListViewItem)
        Dim lstTasks As New List(Of Task)()
        Dim decTotal As Decimal = 0.0
        For i As Int32 = 0 To lstItem.Count - 1
            Dim j As Int32 = i
            Dim t As Task = Task.Run(Sub()
                                         lstViewItem.Add(New ListViewItem(New String() {j, lstItem(j).Process()}))
                                         'System.Threading.Thread.Sleep(j * 1000)
                                         decTotal += lstItem(j).Value
                                     End Sub)
            lstTasks.Add(t)
        Next
        Task.WaitAll(lstTasks.ToArray())
        lstView.Items.AddRange(lstViewItem.ToArray())
        lstView.Items.Add("")
        lstView.Items.Add(decTotal)
    Catch ex As Exception
        Debug.WriteLine(ex.Message)
    End Try

您应该可以使用 SyncLock 来解决您的问题。 SyncLock 只能用于引用类型。所需要的只是创建一个在当前实例范围内的新对象,然后让 SyncLock 锁定该对象。

这是一个利用 SyncLock 的小型控制台应用程序。我大大简化了你所拥有的。我真的不想制作 listViews 之类的,而不是返回一个随机小数,它只是 returns 1 这样结果应该是循环迭代的次数。

Option Strict On
Option Explicit On

Imports System.Threading.Tasks

Module Module1
    Sub Main()
        Dim lstTasks As New List(Of Task)()
        Dim SyncLockedTotal As Decimal = 0D
        Dim decTotal As Decimal = 0D
        Dim sLock As New Object
        For i As Int32 = 1I To 1000I
            Dim t As Task = Task.Run(Sub()
                                         Dim tempDecimal As Decimal = clsItem.Process()
                                         decTotal += tempDecimal
                                         SyncLock sLock
                                             SyncLockedTotal += tempDecimal
                                         End SyncLock
                                     End Sub)
            lstTasks.Add(t)
        Next
        Task.WaitAll(lstTasks.ToArray())
        Console.WriteLine(String.Format("Value for decTotal: {0}", decTotal.ToString))
        Console.WriteLine(String.Format("Value for SyncLockedTotal: {0}", SyncLockedTotal.ToString))

        Console.ReadLine()
    End Sub
End Module

Public Structure clsItem
    Public Shared Function Process() As Decimal
        Dim rnd As New Random(DateTime.Now.Millisecond)
        Threading.Thread.Sleep(rnd.Next(10I))
        Return 1D
    End Function
End Structure

注意:您的应用程序设置必须以 .NET 4.5 为目标才能使用 Task.Run(),如果您以 .NET 4 为目标,则必须使用 Task.Factory.StartNew()。如果您的目标是 .NET 3.5 或更低版本,这对您不起作用,因为您没有可用的 System.Threading.Tasks 命名空间。