并发/同时多线程任务(VB.NET)

时间:2016-07-24 18:01:58

标签: vb.net multithreading concurrency

我有一个整数列表,其中包含在一组批次中发生特定数字组合的次数,其中每次迭代中出现1到80个20个数字。

让我们说LotCount = 1并且我们正在计算nChoose2组合。 整数计数列表将为80Choose2 = 3,160,每个组合最少出现0次,最多为1次(因为LotCount = 1)。在这个例子中,我们恰好有20Choose2 = 190 1&s;其余为0,但是对于LotCount = 2或更多,它最多为20Choose2 * LotCount和min 20Choose2。

这很容易失控,因为即使LotCount仍然是1,当探测大于" 2"组合,其数量呈指数增长。 20选择3 = 82,160 - 20选择4 = 1,581,580等等

我想要做的是同时并以多线程方式计算出现次数,以便所有CPU内核都能正常工作,因为这是一项非常耗时的任务。

我试图这样做搜索谷歌和东西,但我想我只有"并发"因为应用程序在我的8线程计算机上的CPU使用率高达13%

这是我的原始代码:

        Dim DBNumFrom As New List(Of Integer)
        Dim DBNumTo As New List(Of Integer)
        Dim k As Integer = CInt(nudFindNGrams.Value)
        Dim KinoCombinations As New List(Of List(Of Integer))
        Dim KinoCombinationsFrequencyIndexes As New List(Of clsNGram)
        KinoCombinations = nChooseK(KinoNumbers, k)
        ...............................
        Await Task.Run(
        Sub()
            For i = 0 To KinoCombinations.Count - 1
                KinoCombinationsFrequencyIndexes.Add(New clsNGram With {.nGramCombination = KinoCombinations(i), .Occurrences = 0})

                For l = 0 To DBNumFrom.Count - 1
                    For j = DBNumFrom(l) To DBNumTo(l) Step -1
                        Dim CombinationIsContainedInCurrentLot As Boolean = True
                        For f As Integer = 0 To k - 1
                            If Not KinoGames.Item(j).NumbersArray.Contains(KinoCombinations(i)(f)) Then
                                CombinationIsContainedInCurrentLot = False
                                Exit For
                            End If
                        Next

                        If CombinationIsContainedInCurrentLot Then KinoCombinationsFrequencyIndexes(i).Occurrences += 1
                    Next
                Next

            Next
            End Sub)

经过一番阅读后,我将其改为:

[稍后我称之为并发的函数]

Private Async Function CalcKinoCombinations(ByVal FromIndex As Integer, ByVal ToIndex As Integer, ByVal k As Integer, ByVal KinoCombinations As List(Of List(Of Integer)), DBNumFrom As List(Of Integer), DBNumto As List(Of Integer)) As Task(Of List(Of clsNGram))
    Dim KinoCombinationsFrequencyIndexes As New List(Of clsNGram)
    Dim Counter As Integer = -1
    For i = FromIndex To ToIndex
        Counter += 1
        KinoCombinationsFrequencyIndexes.Add(New clsNGram With {.nGramCombination = KinoCombinations(i), .Occurrences = 0})

        For l = 0 To DBNumFrom.Count - 1
            For j = DBNumFrom(l) To DBNumto(l) Step -1
                Dim CombinationIsContainedInCurrentLot As Boolean = True
                For f As Integer = 0 To k - 1
                    If Not KinoGames.Item(j).NumbersArray.Contains(KinoCombinations(i)(f)) Then
                        CombinationIsContainedInCurrentLot = False
                        Exit For
                    End If
                Next

                If CombinationIsContainedInCurrentLot Then KinoCombinationsFrequencyIndexes(Counter).Occurrences += 1
            Next
        Next

    Next
    Return KinoCombinationsFrequencyIndexes
End Function

[按钮子内的代码]

        Dim CountSwarmsTasksQuery As New List(Of Task(Of List(Of clsNGram)))
        If KinoCombinations.Count > CoresCount Then
            Dim intCombinationsPerIteration As Integer = CInt(Math.Floor(KinoCombinations.Count / CoresCount))
            For i As Integer = 1 To CoresCount
                If i = 1 Then
                    CountSwarmsTasksQuery.Add(CalcKinoCombinations(0, intCombinationsPerIteration, k, KinoCombinations, DBNumFrom, DBNumTo))
                ElseIf i < CoresCount Then
                    CountSwarmsTasksQuery.Add(CalcKinoCombinations((intCombinationsPerIteration * i) - intCombinationsPerIteration + 1, intCombinationsPerIteration * i, k, KinoCombinations, DBNumFrom, DBNumTo))
                Else
                    CountSwarmsTasksQuery.Add(CalcKinoCombinations((intCombinationsPerIteration * i) - intCombinationsPerIteration + 1, KinoCombinations.Count - 1, k, KinoCombinations, DBNumFrom, DBNumTo))
                End If
            Next

        Else
            CountSwarmsTasksQuery.Add(CalcKinoCombinations(0, KinoCombinations.Count - 1, k, KinoCombinations, DBNumFrom, DBNumTo))
        End If
        Dim CountSwarmsTasks As Task(Of List(Of clsNGram))() = CountSwarmsTasksQuery.ToArray
        Dim CountSwarmsLstClsNGram() As List(Of clsNGram) = Await Task.WhenAll(CountSwarmsTasks)
        For Each item In CountSwarmsLstClsNGram
            KinoCombinationsFrequencyIndexes.AddRange(item)
        Next

但正如我所说,从我收集的内容中,并发性存在,但这一切都发生在1个线程中,因为这是一个需要cpu的任务,我从中得不到任何好处。我需要并发和每个任务都在一个单独的线程上。

[信息]

我所做的基本上是取nChoosek计数列表并将其除以8(CoreCount变量在我的计算机上返回8)。 订单确实发挥了作用,我喜欢&#34;。当所有&#34;将按照我称之为的顺序返回

如何将8个任务中的每个任务放入不同的线程,然后按照我调用的顺序获取函数结果(List(Of clsNGram)))?

我真的很感谢帮助 - 谢谢你们

1 个答案:

答案 0 :(得分:0)

事实证明,我自己想通了,我想我会发布它,以防其他人想要完成相同的任务(将任务划分为多个以并发和多线程方式运行的子任务) )

以下是代码:

Public Structure MyStructure
Dim DateAndTime As Date
Dim Numbers() As Integer
Public Overrides Function ToString() As String
    Return DateAndTime.ToString("dd/MM/yyyy HH:mm") & " " & Numbers(0).ToString & " " & Numbers(1).ToString & " " & Numbers(2).ToString
End Function
End Structure


Public Class Form1

Dim MyDesign As New List(Of MyStructure)
Dim strMyDesign As New List(Of String)

Public Async Function LoadMyDesign(ByVal FromLineIndex As Integer, ByVal ToLineIndex As Integer, ByVal FilePaths() As String) As Task(Of List(Of MyStructure))
    Dim CurMyDesign As New List(Of MyStructure)

    Await Task.Run(
        Sub()
            For j As Integer = FromLineIndex To ToLineIndex
                Dim FileLines() As String = File.ReadAllLines(FilePaths(j))

                For i = 0 To FileLines.Length - 1
                    Dim LineContent() As String = FileLines(i).Split(","c)
                    Dim NewDesign As New MyStructure With {.DateAndTime = Date.Parse(LineContent(0)), .Numbers = (From Num In LineContent Skip 1 Select CInt(Num)).ToArray}

                    CurMyDesign.Add(NewDesign)
                Next
            Next
        End Sub)

    Return CurMyDesign
End Function

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim DesignsQuery As New List(Of Task(Of List(Of MyStructure)))
    Dim FilesPaths() As String = Directory.GetFiles("c:\users\giannism\documents\visual studio 2015\Projects\WindowsApplication2\WindowsApplication2\bin\Release" & "\Files\")
    Dim FilesPaths() As String = Directory.GetFiles(My.Application.Info.DirectoryPath & "\Files\")
    Dim IndicesPerIteration As Integer = CInt(Math.Floor(FilesPaths.Length / Environment.ProcessorCount))

    MyDesign.Clear()
    strMyDesign.Clear()
    Button1.Enabled = False

    If FilesPaths.Length >= Environment.ProcessorCount Then
        For i = 1 To Environment.ProcessorCount
            Dim CurIteration As Integer = i
            If CurIteration = 1 Then
                DesignsQuery.Add(LoadMyDesign(0, IndicesPerIteration - 1, FilesPaths))
            ElseIf CurIteration < Environment.ProcessorCount Then
                DesignsQuery.Add(LoadMyDesign(((IndicesPerIteration) * (CurIteration - 1)), ((IndicesPerIteration) * CurIteration) - 1, FilesPaths))
            Else
                DesignsQuery.Add(LoadMyDesign(((IndicesPerIteration) * (CurIteration - 1)), FilesPaths.Length - 1, FilesPaths))
            End If
        Next

        Dim sth As List(Of MyStructure)() = Await Task.WhenAll(DesignsQuery)
        For Each Item As List(Of MyStructure) In sth
            MyDesign.AddRange(Item)
        Next

    Else
        MyDesign = Await LoadMyDesign(0, FilesPaths.Length - 1, FilesPaths)
    End If

    strMyDesign.AddRange((From l As MyStructure In MyDesign Select (l.ToString())).Take(10))
    ListBox1.DataSource = Nothing
    ListBox1.DataSource = strMyDesign
    Button1.Enabled = True
End Sub

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    MyDesign.Clear()
    strMyDesign.Clear()
    ListBox1.DataSource = Nothing
End Sub

End Class

要使其工作,需要在“FilesPaths”变量指向的目录中存在服务器文件

文件必须包含以下行:

28/8/2016 18:00, 1, 2, 3
28/8/2016 18:01, 4, 5, 6
28/8/2016 18:02, 7, 8, 9
28/8/2016 18:03, 10, 11, 12
28/8/2016 18:04, 1, 2, 3
28/8/2016 18:05, 4, 5, 6
28/8/2016 18:06, 7, 8, 9
28/8/2016 18:07, 10, 11,12
28/8/2016 18:08, 1, 2, 3
28/8/2016 18:09, 4, 5, 6
28/8/2016 18:10, 7, 8, 9
28/8/2016 18:11, 10, 11, 12
28/8/2016 18:12, 1, 2, 3
28/8/2016 18:13, 4, 5, 6
28/8/2016 18:14, 7, 8, 9
28/8/2016 18:15, 10, 11, 12

(P.S。如果你觉得这很有帮助,请给我+声望,因为有些事情需要15岁以上的声誉而且我是新来的,所以还没有得到那个部分)