数组问题不够长

时间:2015-03-24 17:17:16

标签: vb.net

我每分钟调用此函数数千次以获得平均延迟但在运行约20或30分钟后我的应用程序崩溃..任何想法为什么会发生这种情况?

源数组不够长。检查srcIndex和length,以及数组的下限。

Dim iLatency_Average As New List(Of Long)
Public Function Average_Latency(myLatency As Long) As Long

    iLatency_Average.Insert(0, myLatency)

    If iLatency_Average.Count = 25 Then
        Dim allLatency() As Long = iLatency_Average.ToArray()

        Array.Sort(allLatency)

        Dim iAverage As Long
        For i As Integer = 5 To 19
            iAverage += allLatency(i)
        Next

        iLatency_Average.RemoveAt(24)

        Return CLng(iAverage / 15)
    Else
        Return 0
    End If
End Function

3 个答案:

答案 0 :(得分:2)

由于您希望保证最后25次观察的滑动窗口,因此不使用锁定可能会出现问题。不过,这是一个相对便宜的锁。

正如@the_lotus所提到的,将队列操作与实际平均分开要快得多。

请参阅下面的代码,其中包含10个任务,每个任务会增加100,000个延迟。我平均每1,000,000次操作约400毫秒。包含ArraySegment(Of Long)和LINQ选项以进行比较。

Private RecentLatencies As New Queue(Of Long)

Public Sub Main()
    With New Stopwatch
        .Start()

        Task.WhenAll(Enumerable.Range(1, 10).Select(Function(x) Task.Run(Sub()
                                                                            For m = 1 To 100000
                                                                                LogLatencyAndGetSlidingAverage(m)
                                                                            Next
                                                                         End Sub))).Wait()

        .Stop()

        Console.WriteLine("All done...{0}ms", .ElapsedMilliseconds)
        Console.ReadKey()
    End With
End Sub

Private Function LogLatencyAndGetSlidingAverage(latency As Long) As Long
    Dim l As Long() = Nothing

    SyncLock RecentLatencies
        RecentLatencies.Enqueue(latency)

        If RecentLatencies.Count = 25 Then
            l = RecentLatencies.ToArray()
            RecentLatencies.Dequeue()
        End If
    End SyncLock

    'option 1
    If l IsNot Nothing Then
        Array.Sort(l)

        Dim sum As Long

        For i = 5 To 19
            sum += l(i)
        Next

        Return sum \ 15
    Else
        Return 0
    End If

    'option 2 - ArraySegment
    'If l IsNot Nothing Then
    '    Array.Sort(l)
    '    Return CLng(New ArraySegment(Of Long)(l, 5, 15).Average)
    'Else
    '    Return 0
    'End If

    'option 3 - LINQ
    'Return CLng(If(l IsNot Nothing, l.OrderBy(Function(n) n).Skip(5).Take(15).Average, 0))
End Function

答案 1 :(得分:0)

您可以使用SyncLock。此外,您似乎使用Queue的属性,而不是列表。请注意,每次使用该集合时都必须调用SyncLock。

Dim iLatency_Average As New Queue(Of Long)

Public Function Average_Latency(ByVal myLatency As Long) As Long

    Dim allLatency() As Long = Nothing

    ' Add the new latency
    SyncLock iLatency_Average
        iLatency_Average.Enqueue(myLatency)

        If iLatency_Average.Count = 25 Then
            allLatency = iLatency_Average.ToArray()
            iLatency_Average.Dequeue()
        End If
    End SyncLock

    ' Calculate average
    If allLatency IsNot Nothing Then
        Array.Sort(allLatency)

        Dim iAverage As Long
        For i As Integer = 5 To 19
            iAverage += allLatency(i)
        Next

        Return CLng(iAverage / 15)
    Else
        Return 0
    End If
End Function

我还将你的逻辑分成两部分。一部分是添加新值,另一部分是计算平均值。

答案 2 :(得分:0)

此版本不使用SyncLock,但速度很慢,但它使用了对BlockingCollection的评论发布的建议。

Dim iLatency_Average As New Concurrent.BlockingCollection(Of Long)(25)
Public Function Average_Latency(myLatency As Long) As Long

    iLatency_Average.TryAdd(myLatency)

    If iLatency_Average.Count = 25 Then
        Dim allLatency() As Long = iLatency_Average.ToArray

        Array.Sort(allLatency)

        Dim iAverage As Long
        For i As Integer = 5 To 19
            iAverage += allLatency(i)
        Next

        iLatency_Average.TryTake(0)

        Return CLng(iAverage / 15)
    Else
        Return 0
    End If
End Function