高CPU使用率 [英] High CPU Utilization

查看:132
本文介绍了高CPU使用率的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好,
我有一个侦听器线程,它侦听UDP事务并将它们排队入_TransactionQ,我还有另一个线程从_TransactionQ出队事务,它将进行大量处理以确认事务的正确顺序,同时具有根据序列号检测丢失的事务并向服务器请求重新加载的逻辑,该线程将在_ConfirmedMessageQueue中对已确认的事务进行排队.
我使用SyncLock来同步对三个队列的访问.
我有CPU使用率高(70%-80%)的问题!!!!

Hello,
I have a listener thread that listens to UDP transactions and en-queue them into _TransactionQ, I also have another thread that de-queue the transactions from _TransactionQ, it will do a lot of processing to confirm the correct order of the transactions, it also has a logic to detect missing transactions based on a sequence number and to request a reload from the server, this thread will en-queue the confirmed transactions in _ConfirmedMessageQueue.
I use SyncLock to Synchronize access to the three Queues.
I have a problem with high CPU utilization (70%-80%)!!!!

Imports System.Net
Imports System.Net.Sockets
Imports System.Threading

Public Class UDPListener

#Region "Variables"
    Private _port As Integer
    Private _listenThread As Thread ''Queue thread
    Private _dequeueThread As Thread ''DeQueue thread
    Private _ListenThreadIsAlive As Boolean
    Private _DequeueThreadIsAlive As Boolean
    Private _receivedData As String
    Private _udpClient As UdpClient
    Private _mySequenceNumber As Integer
    Private _address As String
    Private _ConfirmedMessageQueue As Queue
    Private _TransactionQ As Queue
#End Region

#Region "Properties"
    Public Property ListenThreadIsAlive() As Boolean
        Get
            Return _ListenThreadIsAlive
        End Get
        Set(ByVal value As Boolean)
            _ListenThreadIsAlive = value
        End Set
    End Property

    Public Property DequeueThreadIsAlive() As Boolean
        Get
            Return _DequeueThreadIsAlive
        End Get
        Set(ByVal value As Boolean)
            _DequeueThreadIsAlive = value
        End Set
    End Property

    Public ReadOnly Property udpClient() As UdpClient
        Get
            Return _udpClient
        End Get
    End Property

    Public Property mySequenceNumber() As String
        Get
            Return Interlocked.Read(_mySequenceNumber)
        End Get
        Set(ByVal value As String)
            Interlocked.Exchange(_mySequenceNumber, value)
        End Set
    End Property

    Public Property ConfirmedMessageQueue() As Queue
        Get
            Return Queue.Synchronized(_ConfirmedMessageQueue)
        End Get
        Set(ByVal value As Queue)
            _ConfirmedMessageQueue = value
        End Set
    End Property

    Public Property TransactionQ() As Queue
        Get
            Return Queue.Synchronized(_TransactionQ)
        End Get
        Set(ByVal value As Queue)
            _TransactionQ = value
        End Set
    End Property
#End Region

#Region "Events"
    Public Event dataArrived()
#End Region

    ''Constructor
    Sub New(ByVal address As String, ByVal port As Integer, ByVal ExpectedSequenceNumber As Integer)
        Me._port = port
        Me._address = address
        Me.mySequenceNumber = ExpectedSequenceNumber
        Me.initialize()
    End Sub

    Private Sub initialize()
        Try
            ConfirmedMessageQueue = New Queue
            TransactionQ = New Queue
            _listenThread = New Thread(AddressOf listen)
            _dequeueThread = New Thread(AddressOf dequeue)
            _udpClient = New UdpClient(Sockets.AddressFamily.InterNetwork)
            Dim localEP As EndPoint = CType(New IPEndPoint(IPAddress.Any, _port), EndPoint)
            Dim mcastopt As MulticastOption
            mcastopt = New MulticastOption(IPAddress.Parse(_address), IPAddress.Loopback)
            _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1)
            _udpClient.Client.Bind(localEP)
            _listenThread.Name = "udpListenThread"
            _dequeueThread.Name = "udpDequeueThread"
            _ListenThreadIsAlive = True
            _listenThread.Start()
            _DequeueThreadIsAlive = True
            _dequeueThread.Start()
        Catch ex As Exception
            '' Write to log
        End Try
    End Sub

    Private Sub listen()
        _udpClient.JoinMulticastGroup(IPAddress.Parse(Me._address))
        Dim RemoteIpEndPoint As New IPEndPoint(IPAddress.Parse(Me._address), Me._port)
        Dim receiveBytes As [Byte]() = Nothing
        Dim TransactionData As String = ""
        Dim TransactionSeqNum As String = ""
        While _ListenThreadIsAlive

            receiveBytes = _udpClient.Receive(RemoteIpEndPoint)
            If receiveBytes.Count > 0 Then

                TransactionData = Encoding.ASCII.GetString(receiveBytes)
                TransactionSeqNum = TransactionData.Substring(0, TransactionData.IndexOf(Chr(3))).Substring(1)
                TransactionData = TransactionData.Substring(TransactionData.IndexOf(Chr(3)))
                Dim pair As New DictionaryEntry(TransactionSeqNum, TransactionData)
                SyncLock TransactionQ.SyncRoot
                    TransactionQ.Enqueue(pair)
                End SyncLock
            End If
        End While
        Try
            SyncLock _listenThread
                _listenThread.Abort()
            End SyncLock
        Catch ex As Threading.ThreadAbortException
            ''Ignore ThreadAbortException
        End Try
    End Sub

    Private Sub dequeue()
        While _DequeueThreadIsAlive
            Try
                Dim TransactionSeqNum As Integer
                SyncLock TransactionQ.SyncRoot
                    Do While TransactionQ.Count > 0
                        Dim trans As DictionaryEntry
                        trans = TransactionQ.Dequeue
                        ''
                        ''                
                        '' LONG PROCESSING
                        ''
                        ''
                        SyncLock ConfirmedMessageQueue.SyncRoot
                            ConfirmedMessageQueue.Enqueue(_receivedData)
                            incrementMySequenceNumber()
                        End SyncLock ''ConfirmedMessageQueue
                        RaiseEvent dataArrived()
                    Loop
                End SyncLock ''TransactionQ
            Catch ex As Exception
                '' Write to log
            End Try
        End While
        Try
            SyncLock _dequeueThread
                _dequeueThread.Abort()
            End SyncLock
        Catch ex As Threading.ThreadAbortException
            ''Ignore ThreadAbortException
        End Try
    End Sub

    ''Thread safe increment for mySequenceNumber
    Private Sub incrementMySequenceNumber()
        Interlocked.Increment(_mySequenceNumber)
    End Sub
    
    '' close connection, abort thread
    Public Sub stopListening()
        If Not IsNothing(_udpClient) Then
            If _listenThread.IsAlive Then
                _ListenThreadIsAlive = False
            End If
            If _dequeueThread.IsAlive Then
                _DequeueThreadIsAlive = False
            End If
            _udpClient.Close()
            CType(_udpClient, IDisposable).Dispose()
        End If
    End Sub

    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub
End Class

推荐答案

您的线程任务每秒运行数千次相同的检查,而根本没有代码可以放弃控制和等待. />
查看您的dequeue方法在做什么.它将连续分配TransactionSeqNum,获取一个锁,如果有TransactionQ记录,则执行另一个循环,释放该锁,释放TransactionSeqNum,然后返回到开始-大约一百万个提姆,因为其中没有代码.在这里使线程进入睡眠状态以等待工作显示.

您正在进行大量轮询,这就是为什么代码占用CPU的原因.
还有,这一切的重点是什么?我看到的是在复制MS Message Queue所做的工作中效率很低的尝试.如果您曾经使用过,可以避免编写所有这些代码,而直接从事事务处理.
Your thread tasks are running the same checks thousands of times a second, with no code in there at all that gives up control and waits.

Look at what your dequeue method is doing. It''s going to continuously allocate TransactionSeqNum, grab a lock, execute another loop if there are TransactionQ records, release the lock, release the TransactionSeqNum, and go back to the beginning - about a million tims a second since there is no code in here that puts the thread to sleep to wait for work to show up.

You''re doing a ton of polling which is why your code is hogging the CPU.

Also, what''s the point of all this?? What I see is a very inefficient attempt at duplicating what MS Message Queue does. Had you used that you could have avoided writing ALL of this code and just gotten down to the business of handling transactions.


这篇关于高CPU使用率的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆