高CPU使用率 [英] High CPU Utilization
问题描述
你好,
我有一个侦听器线程,它侦听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 yourdequeue
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屋!