加速"老"字符串使用PLINQ或Async / Await或TPL等解析方法

时间:2017-07-05 10:58:08

标签: vb.net parsing asynchronous parallel-processing plinq

作为(希望)所有开发人员,我多年来一直在开发,现在正处于OOP和函数式编程的日常成本之中。最近我碰到了老了" (2年)我读取TCP流的DLL,将传入的字符串(以换行符结尾)放入ConcurrentQueue(Of String)。然后第二个Backgroundworker遍历ConcurrentQueue(Of String)并将字符串出列并解析它。

根据我发送给TCP服务器的请求命令,我得到一行或几行。此外,当没有任何要求时,TCP服务器什么都不发送。这完全是事件驱动的。

随着新的高效技术PLINQ,Async / Await和TPL,我决定让它更快/更高效。目前我正在集思广益,如何做到这一点,并要求你和我一起思考或给出一些好的建议。

让我们深入了解我现在拥有的东西: 它首先从两个背景工作者开始,一个用于阅读,一个用于解析。

阅读背景工作者: 这个后台工作者的工作是读取输入数据,并确保继续阅读,直到换行通过。然后它切成一个字符串并将其放入ConcurrentQueue(Of String)。代码如下所示:

Private Sub bgwReceive_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgwTCP_Receive.DoWork

    Dim strRXData As String = String.Empty
    Dim intLfpos As Integer = 0

    Try
        Do Until bgwTCP_Receive.CancellationPending

            'while the client is connected, continue to wait for and read data
            While _Client.Connected AndAlso _ClientStream.CanRead
                Dim buffer(_Client.ReceiveBufferSize - 1) As Byte
                Dim read As Integer = _ClientStream.Read(buffer, 0, buffer.Length)

                'Put the new data in the queue
                If read > 0 Then

                    'Add incomming data to the buffer string
                    strRXData &= Text.Encoding.ASCII.GetString(buffer, 0, read)

                    'Replace "0 padding"
                    strRXData.Replace(Chr(0), String.Empty)

                    'Now check if we have a Linefeed in our buffer string
                    While strRXData <> String.Empty

                        'Get the position of the first linefeed
                        intLfpos = strRXData.IndexOf(vbLf)

                        'Now check if we find something.
                        If intLfpos < 0 Then Exit While

                        'There is a line feed, it is time to add it to the incomming data queue
                        IncommingData.Enqueue(strRXData.Substring(0, intLfpos - 1))

                        'Now remove the command from the buffer string
                        strRXData = strRXData.Substring(intLfpos + 1, strRXData.Length - intLfpos - 1)

                    End While
                End If

                'Check if we have to stop
                If bgwTCP_Receive.CancellationPending Then e.Cancel = True : Exit Do

                Threading.Thread.Sleep(1)
            End While

            Threading.Thread.Sleep(100)
        Loop

        e.Cancel = True

    Catch op As OperationCanceledException
        Throw New Exception("TCP Reading cancelled")
    Catch se As SocketException
        Throw New Exception("Socket unknown error. Native error code: " & se.NativeErrorCode)
    Catch IOex As IOException
        Throw New Exception("Socket timeout while receiving data from [" & TCP_ServerIP.ToString & "]")
    End Try
End Sub

Parsing Backgroundworker:这个backgroundworker工作是解析ConcurrentQueue(Of String)中的字符串。在这个背景工作者中,有一个大的Select案例,它会查看字符串中的第一个单词。这决定了该怎么做。

收到的协议非常简单,但不幸的是它没有像JSON这样的索引结构。字符串看起来像这样:IND PARM1:&#34; Hello world!&#34; PARM2:1.4.8 \ CrLf

正如您所看到的,它非常简单明了。 IND表示命令,如VER用于VERSION字符串。 IND总是3个字符长。然后是参数。参数名称总是4个字符长。如果它在双引号之间,它是一个字符串,否则它就像一个双/整数/ IP地址(X.X.X.X)。请记住原始它是一个字符串。在我的解析器中,我将其解析为对象属性。代码如下所示:

Private Sub bgwProcessQueue_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgwProcessQueue.DoWork

    Dim strNewLine As String = String.Empty
    Dim strSubLine As String = String.Empty

    Try
        'Loop until program has stopped
        Do Until bgwProcessQueue.CancellationPending

            'Only process when something is in the queue
            If TCP_Connection.IncommingData.TryDequeue(strNewLine) Then

                'If Backgroundworker has to cancel than cancel
                If bgwProcessQueue.CancellationPending Then Exit Do

                Select Case True

                    Case strNewLine.StartsWith("VER") 'Example:     VER PRM1:1.1 PRM2:"Hi there" PRM3:1.1.1 PRM4:8/0 PRM5:8

                        'First check if all the needed values are there, if not resend the command
                        If strNewLine.Contains("PRM1:") AndAlso strNewLine.Contains("PRM2:") AndAlso strNewLine.Contains("PRM3:") AndAlso strNewLine.Contains("PRM4:") AndAlso strNewLine.Contains("PRM5:") Then

                            'Get versions and devicename
                            Me.Param1 = GetSubstring(strNewLine, "PRM1:", " ")
                            Me.Param2 = GetSubstring(strNewLine, "PRM2:", " ")
                            Me.Param3 = GetSubstring(strNewLine, "PRM3:", " ")
                            Me.Param4 = GetSubstring(strNewLine, "PRM4:", " ")
                            Me.Param5 = GetSubstring(strNewLine, "PRM5:", " ")

                        Else
                            'Commando was invalid, resend the command
                            Log.Message(LogLevel.Warning, "VER Messages was incompleet, resending VER command")
                            SendData("VER")
                        End If

                    Case strNewLine.StartsWith("ERROR")
                        Log.Message(LogLevel.Warning, strNewLine)
                End Select
            End If

            'Clear any old data
            strNewLine = String.Empty

            'Sleep
            Threading.Thread.Sleep(1)
        Loop

        e.Cancel = True
    Catch ex As Exception
        Log.Exception(ex)
    End Try
End Sub

Private Function GetSubstring(text As String, StartValue As String, EndValue As String) As String

    Try
        'If we can't find the Start value we can't do anything
        If Not text.Contains(StartValue) Then Return String.Empty

        'Find the index of the Start and End value
        intStartValueIndex = text.IndexOf(StartValue) + StartValue.Length
        intEndValueIndex = text.IndexOf(EndValue, intStartValueIndex)

        'If no Endvalue index was found then get the end of the string
        If intEndValueIndex < intStartValueIndex Then intEndValueIndex = text.Length

        'Return the substring en remove quetes
        Return text.Substring(intStartValueIndex, intEndValueIndex - intStartValueIndex).Replace("""", "")
    Catch ex As Exception
        Log.Exception(ex)
        Return String.Empty
    End Try
End Function

希望以上所有内容都是可以理解的。我正在考虑使用Parrallel.ForEach循环遍历ConcurrentQueue(Of String),并将Dequeued字符串传递给执行解析的sub。在阅读方面,我的灵感目前是空的......

0 个答案:

没有答案