我每分钟调用此函数数千次以获得平均延迟但在运行约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
答案 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