我最近开始了一份新工作,这里有一个 Windows 服务,它使用来自私有(private) Windows 队列的消息。该服务仅在上午 9 点到下午 6 点之间使用消息。因此,在晚上 7 点到早上 8:59 期间,它会在队列中积累大量消息。当它在晚上 9 点开始处理时,服务的 CPU 使用率会很高(98%、99%),这会影响服务器的性能。
此服务使用线程来处理队列的消息,但由于我之前从未使用过线程,所以我有点迷茫。
这是我确定会发生这种情况的代码部分:
private Thread[] th;
//in the constructor of the class, the variable th is initialized like this:
this.th = new Thread[4];
//the interval of this method calling is 1sec, it only goes high cpu usage when there is a lot of messages in the queue
public void Exec()
{
try
{
AutoResetEvent autoEvent = new AutoResetEvent(false);
int vQtd = queue.GetAllMessages().Length;
while (vQtd > 0)
{
for (int y = 0; y < th.Length; y++)
{
if (this.th[y] == null || !this.th[y].IsAlive)
{
this.th[y] = new Thread(new ParameterizedThreadStart(ProcessMessage));
this.th[y].Name = string.Format("Thread_{0}", y);
this.th[y].Start(new Controller(queue.Receive(), autoEvent));
vQtd--;
}
}
}
}
catch (Exception ex)
{
ExceptionPolicy.HandleException(ex, "RECOVERABLE");
}
}
编辑:我正在尝试 Brian Gideon 发布的第二种方法。但老实说:我对代码深感困惑,我不知道它在做什么。
我没有改变创建 4 个线程的方式和我展示的其他代码,只是将我的 Exec(exec 是在上午 9 点到下午 6 点时每秒调用的方法)方法更改为:
public void Exec()
{
try
{
AutoResetEvent autoEvent = new AutoResetEvent(false);
int vQtd = queue.GetAllMessages().Length;
while (vQtd > 0)
{
for (int i = 0; i < 4; i++)
{
var thread = new Thread(
(ProcessMessage) =>
{
while (true)
{
Message message = queue.Receive();
Controller controller = new Controller(message, autoEvent);
//what am I supposed to do with the controller?
}
});
thread.IsBackground = true;
thread.Start();
}
vQtd--;
}
}
catch (Exception ex)
{
ExceptionPolicy.HandleException(ex, "RECOVERABLE");
}
}
最佳答案
哎呀。我必须诚实。这不是一个很好的设计。它很可能围绕 while
循环旋转,等待前面的线程完成处理。这是一个更好的方法。请注意,这 4 个线程仅创建一次并永远存在。下面的代码使用 BlockingCollection来自 .NET 4.0 BCL。如果您使用的是早期版本,您可以将其替换为 Stephen Toub 的 BlockingQueue .
注意:您的情况可能需要进一步重构。此代码试图保留原始代码中的一些常见元素。
public class Example
{
private BlockingCollection<Controller> m_Queue = new BlockingCollection<Controller>();
public Example()
{
for (int i = 0; i < 4; i++)
{
var thread = new Thread(
() =>
{
while (true)
{
Controller controller = m_Queue.Take();
// Do whatever you need to with Contoller here.
}
});
thread.IsBackground = true;
thread.Start();
}
}
public void Exec()
{
try
{
AutoResetEvent autoEvent = new AutoResetEvent(false);
int vQtd = Queue.GetAllMessages().Length
while (vQtd > 0)
{
m_Queue.Add(new Controller(Queue.Receive(), autoEvent));
}
}
catch (Exception ex)
{
ExceptionPolicy.HandleException(ex, "RECOVERABLE");
}
}
}
编辑:
或者更好,因为 MessageQueue
是线程安全的:
public class Example
{
public Example()
{
for (int i = 0; i < 4; i++)
{
var thread = new Thread(
() =>
{
while (true)
{
if (/* between 9am and 6pm */)
{
Message message = queue.Receive();
Controller controller = new Controller(message, /* AutoResetEvent? */);
// Do whatever you need to with Contoller here.
// Is the AutoResetEvent really needed?
}
}
});
thread.IsBackground = true;
thread.Start();
}
}
}
关于c# - Windows服务应用程序的CPU使用率高,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3525104/