c# - Windows服务应用程序的CPU使用率高

标签 c# .net multithreading

我最近开始了一份新工作,这里有一个 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/

相关文章:

c# - 什么时候应该使用 Moq 的 .As 方法?

c++ - 使用线程的意外行为

C# - GetMethod 返回 null

c# - 无法调试 Razor 助手 - 似乎 IIS 没有使用调试符号进行编译?

.NET "Push"技术?

c# - ArrayList 的.NET 并行处理

c# - 使用 C# 代码从 Active Directory 获取当前登录

c# - 在字典的 linq 迭代过程中,什么可能导致堆栈溢出?

multithreading - 关于 Goroutines 的 Golang 内存泄漏

c# - 在 WIn UI 中配置 httpClient