我正在使用.NET任务来获得多线程的优势,但实现起来并不容易。
为了证明我遇到的问题,我写了一个我实际代码的简化版本。
执行代码后,您意识到最终的AllResults字典确实具有KeyValuepairs(Nothing,Nothing) - 这是不可能添加的。
在思考了一下之后,我想我发现了为什么会发生这种情况,但我找不到解决方案。
我猜这种情况正在发生,因为子任务正在将主键级字典“AllResults”中的keyvaluepairs添加得太快 - 当字典达到它的大小时,不允许它分配更多空间。 据我所知,当字典变满时,字典会自动调整为当前大小的两倍。但我想由于使用任务(在其他线程上运行),在调整自身大小时它会获得两倍以上,这会导致Nothing(null)元素。
.NET必须尝试通过添加元素(无,无)来防止内存访问错误(可能是蓝屏)。实际上,这是一个很好的行为,并证明了Dictionaries如何在.NET中编写得很好。它可能会跳过添加但我们可能不知道会导致数据丢失的错误。
但是,如何解决这个问题?
谢谢你们。
Imports System.Threading.Tasks
Module Module1
Public AllResults As Dictionary(Of Integer, SomeClass) 'this is the issue
Public Class SomeClass
Public Property ID As Integer
Public Property Name As String
Public ADictionary As Dictionary(Of Integer, Integer) = New Dictionary(Of Integer, Integer)
Public subClasses As Dictionary(Of Integer, SomeClass)
Public Sub New()
End Sub
End Class
Sub Main()
AllResults = New Dictionary(Of Integer, SomeClass)
Dim Classes As Dictionary(Of Integer, SomeClass) = New Dictionary(Of Integer, SomeClass)
Classes.Add(10, New SomeClass With {.ID = 1, .Name = "10"})
Classes.Add(20, New SomeClass With {.ID = 2, .Name = "20"})
Classes.Add(40, New SomeClass With {.ID = 3, .Name = "40"})
Classes.Add(80, New SomeClass With {.ID = 4, .Name = "80"})
Classes.Add(160, New SomeClass With {.ID = 5, .Name = "160"})
Classes.Add(320, New SomeClass With {.ID = 6, .Name = "320"})
Classes.Add(640, New SomeClass With {.ID = 7, .Name = "640"})
Classes.Add(1280, New SomeClass With {.ID = 8, .Name = "1280"})
Dim MainTasks(Classes.Count - 1) As Task
Dim MTX As Integer = 0
Dim Depth As Integer = 3
For Each sc As SomeClass In Classes.Values
MainTasks(MTX) = Task.Factory.StartNew(Sub()
DoCalculation(sc, Depth)
End Sub)
MTX += 1
Next
Task.WaitAll(MainTasks)
Console.WriteLine("Completed.")
Dim IE As IOrderedEnumerable(Of KeyValuePair(Of Integer, SomeClass))
IE = AllResults.OrderBy(Function(v) v.Value.ID)
For Each vkvp As KeyValuePair(Of Integer, SomeClass) In IE
Next
Console.ReadLine()
End Sub
Public Function DoCalculation(inputClass As SomeClass, depth As Integer) As Dictionary(Of Integer, SomeClass)
'do some work here
Dim newID As Integer, newClass As SomeClass
inputClass.subClasses = New Dictionary(Of Integer, SomeClass)
For x As Integer = 10 To 20
newID = Integer.Parse(inputClass.ID.ToString + x.ToString)
newClass = CloneClass(inputClass)
newClass.ID = newID
inputClass.subClasses.Add(x, newClass)
Next
If depth > 0 Then
Dim SubTasks(inputClass.subClasses.Count - 1) As Task
Dim STX As Integer = 0
For Each c As SomeClass In inputClass.subClasses.Values
AllResults.Add(c.ID, c)
SubTasks(STX) = Task.Factory.StartNew(Sub()
DoCalculation(c, depth - 1)
End Sub, TaskCreationOptions.AttachedToParent)
STX += 1
Next
Task.WaitAll(SubTasks)
End If
Return inputClass.subClasses
End Function
Public Function CloneClass(inputClass As SomeClass) As SomeClass
Dim newClass As SomeClass = New SomeClass
newClass.Name = "Clone of " + inputClass.Name
newClass.ADictionary = New Dictionary(Of Integer, Integer)(inputClass.ADictionary)
Return newClass
End Function
End Module
答案 0 :(得分:3)
Dictionary
不是线程安全的集合(默认情况下,所有.NET对象都不是,除非文档另有说明)。
这意味着当从多个线程同时使用时,它没有被编程为正常工作。
您必须:
AllResults
用法。System.Collections.Concurrent
。