首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CPU使用率过高

CPU使用率过高
EN

Stack Overflow用户
提问于 2014-04-22 22:31:15
回答 3查看 4.9K关注 0票数 3

我在处理一个问题。事实上,我需要在我的程序中使用不同的定时器,而来自框架.Net的定时器不做我期望的事情。所以我决定创建我自己的计时器,但是我的计时器占用了太多的CPU。这是我的密码:

代码语言:javascript
复制
using System;
using System.Threading;

namespace XXXXXXX.Common.Types
{
public delegate void TimerFinishedEventHandler(object sender, EventArgs e);

class Timer
{
    #region Attributes
    private long m_InitialTickCount;
    private long m_Interval;
    private Thread m_Thread;
    private bool m_Enabled;
    #endregion

    #region Events
    public event TimerFinishedEventHandler Finished;
    #endregion

    #region Constructors
    public Timer(long interval, TimerFinishedEventHandler e)
    {
        Finished += e;
        m_Interval = interval;
        Start(m_Interval);
    }
    #endregion

    #region Public methods
    /// <summary>
    /// Start the timer thread.
    /// </summary>
    public void Start(long interval)
    {
        m_Interval = interval;
        m_Enabled = true;
        m_InitialTickCount = Environment.TickCount;

        if (m_Thread == null)
        {
            m_Thread = new Thread(Check);
            m_Thread.Start();
        }
    }

    /// <summary>
    /// Stop the Timer.
    /// </summary>
    public void Stop()
    {
        m_Enabled = false;
    }

    /// <summary>
    /// Restart the Timer.
    /// </summary>
    public void Restart()
    {
        m_InitialTickCount = Environment.TickCount;
    }
    #endregion

    #region Private methods
    /// <summary>
    /// Check if the timer is finished or not.
    /// </summary>
    private void Check()
    {
        while (true)
        {
            if (!m_Enabled)
                return;

            if (Environment.TickCount > m_InitialTickCount + m_Interval)
            {
                OnFinished(EventArgs.Empty);
                return;
            }
        }
    }

    /// <summary>
    /// Called when the Timer is Finished.
    /// </summary>
    /// <param name="e">Event</param>
    protected virtual void OnFinished(EventArgs e)
    {
        if (Finished != null)
            Finished(this, e);
    }
    #endregion
}
}

有人找到解决办法了吗?因为当我启动我的程序时,会创建2到3个计时器,另一个线程运行,我的CPU 100%使用。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-04-22 23:48:56

绝对没有理由你不能有多个定时器。我有数百个计时器的程序,而且在任何时候都可以有少量的计时器在工作。定时器的要点是,它允许您调度周期性操作,而不消耗任何CPU资源,除非实际正在处理这些操作。也就是说,如果您将计时器设置为每分钟勾选一次,则该定时器不会占用线程,不会占用任何内存(超出计时器句柄和回调地址的令牌数量),也不会占用任何CPU资源。只有当计时器“滴答”每分钟一次时,才分配一个线程来执行它的代码。通常这是一个已经存在的池线程,所以线程启动时间可以忽略不计。

使用计时器非常容易:您创建一个方法让计时器执行,然后安排计时器来运行它。例如:

代码语言:javascript
复制
System.Threading.Timer myTimer = 
    new System.Threading.Timer(MyTimerProc, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));

void MyTimerProc(object state)
{
    // do something here
}

您可以使用另一个计时器,它每30秒计时一次,并执行不同的计时器proc:

代码语言:javascript
复制
System.Threading.Timer myOtherTimer = 
    new System.Threading.Timer(MyOtherTimerProc, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));

void MyOtherTimerProc(object state)
{
    // do something else here
}

计时器不会互相干扰。当然,如果计时器进程中的代码修改共享数据(例如,两个进程都试图更新列表或字典),那么您必须同步访问该共享数据或使用并发数据结构。

如果您的计时器过程中的处理时间比计时器周期长,您可能会遇到重入问题。如果MyTimerProc中的处理时间超过60秒,那么可能会出现另一个计时器滴答,现在有两个线程执行该计时器进程。如果您的代码没有设置来处理它,则会导致许多不同类型的问题。通常,您可以通过使计时器成为一次并在每个处理周期结束时重新启动来消除该问题。这里有一些在堆栈溢出上这样做的例子。

System.Timers.Timer是围绕System.Threading.Timer的组件包装器。“为高性能线程优化”或其他类似的想法是愚蠢的。System.Timers.Timer为您提供了一个熟悉的面向事件的接口,并提供了一个SynchronizingObject,它允许您在特定线程上引发事件,而不必像使用System.Threading.Timer那样显式地进行Invoke。通常,这只在UI应用程序中有用。

System.Timers.Timer有一个特别难看的“特性”,我认为这是一个bug:它可以压缩异常。正如文献资料所说:

在.NET Framework2.0和更早版本中,Timer组件捕获并抑制事件处理程序为经过的事件引发的所有异常。

这种行为在.NET 4.5中仍然存在。问题是,如果您有您的Elapsed事件:

代码语言:javascript
复制
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    // do stuff here
}

如果您的事件处理程序抛出异常,它将传播回计时器代码,这会压缩异常,并且永远不会告诉您。实际上,计时器是这样做的:

代码语言:javascript
复制
try
{
    OnTimedEvent(source, args);
}
catch
{
    // Squash those pesky exceptions. Who needs them?
}

这是一个错误隐藏,因为你永远不知道异常是抛出的。所以你的程序不起作用,你也不知道为什么。出于这个原因,我强烈建议您不要使用System.Timers.Timer。使用System.Threading.Timer代替;毕竟,它是构建System.Timers.Timer的基础。

票数 4
EN

Stack Overflow用户

发布于 2014-04-22 22:56:41

要直接回答您的问题,您的CPU使用率这么高的原因是您正在使用一个紧的while循环来检查您经过的事件。这有时被称为自旋锁(调用它是因为它是实现信号量的一种非常低效率的方法,线程在紧循环中检查锁变量,因此它“旋转”)。

您需要阻止并允许其他东西运行一段时间,而不是一个紧密的循环:

代码语言:javascript
复制
private void Check()
{
    while (true)
    {
        if (!m_Enabled)
            return;

        Thread.Sleep(10); //10 millisecond resolution for this timer
        if (Environment.TickCount > m_InitialTickCount + m_Interval)
        {
            OnFinished(EventArgs.Empty);
            return;
        }
    }
}

决议取决于你睡多长时间。尽管如此,提供的计时器应该总是足够的,即使使用2 System.Threading.Timers也可以。我个人使用过System.Threading.Timer和System.Timers.Timer的倍数,没有问题。

当然,对于所有这些定时器,您需要小心地访问共享资源(可能是指现有计时器阻塞其他线程?)。死锁在多线程中是一个非常真实的场景,但与计时器没有多大关系。

票数 2
EN

Stack Overflow用户

发布于 2014-04-23 07:37:10

代表吉姆·米谢尔。

在我的课堂上连接到我的网站,检查数据:

代码语言:javascript
复制
        #region Attributes
        private static Timer m_TimerNextCheck;
        #endregion

        #region Méthodes publiques
        public static void StartCheck()
        {
            Thread licenceThread = new Thread(Checking);
            licenceThread.Start();
        }
        #endregion

        #region Méthodes privées
        private static void Checking()
        {
            //connect to the website

            try
            {
                HttpWebResponse httpWebResponse = (HttpWebResponse) request.GetResponse();

                StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream(), Encoding.Default);

                string response = streamReader.ReadToEnd();

                httpWebResponse.Close();

                if (//Some code)
                {
                    //Some code
                }
                else
                {

                    if (m_TimerNextCheck == null)
                        m_TimerNextCheck = new Timer(TimerNextCheckFinished, null, 300000, Timeout.Infinite);
                    else
                        m_TimerNextCheck.Change(300000, Timeout.Infinite);

                }
            }
            catch (WebException exception)
            {
                //Some code

                if (m_TimerNextCheck == null)
                    m_TimerNextCheck = new Timer(TimerNextCheckFinished, null, 60000, Timeout.Infinite);
                else
                    m_TimerNextCheck.Change(60000, Timeout.Infinite);
            }
        }

        private static void TimerNextCheckFinished(object statusInfos)
        {
            Checking();
        }
        #endregion

在另一班:

代码语言:javascript
复制
    #region Attributs
    private Thread m_ConnectionThread;
    private Timer m_TimerConnectionThread;
    #endregion

    #region Méthodes publiques
    public void Launch()
    {
        m_ConnectionThread = new Thread(Connect);
        m_ConnectionThread.Start();
    }

    public void GetNextMeal()
    {
        //Some code

        if (//Some code)
        {
            //Some code

            if (m_TimerConnectionThread == null)
                m_TimerConnectionThread = new Timer(TimerConnectionThreadFinished, null, 
                    (int)TimeSpan.FromHours(difference.Hour).TotalMilliseconds + 
                    (int)TimeSpan.FromMinutes(difference.Minute).TotalMilliseconds, Timeout.Infinite);
            else
                m_TimerConnectionThread.Change((int)TimeSpan.FromHours(difference.Hour).TotalMilliseconds + 
                    (int)TimeSpan.FromMinutes(difference.Minute).TotalMilliseconds, Timeout.Infinite);
        }
        else
        {
            //Some code
        }
    }

    public void TryReconnect(int minute)
    {
        //Some code

        if (m_TimerConnectionThread == null)
            m_TimerConnectionThread = new Timer(TimerConnectionThreadFinished, null, (int)TimeSpan.FromMinutes(minute).TotalMilliseconds,
                Timeout.Infinite);
        else
            m_TimerConnectionThread.Change((int)TimeSpan.FromMinutes(minute).TotalMilliseconds, Timeout.Infinite);

        //Some code
    }

    //Some code
    #endregion

    #region Méthodes privées
    private void Connect()
    {
        if (m_TimerConnectionThread != null)
            m_TimerConnectionThread.Change(Timeout.Infinite, Timeout.Infinite);

        //Some code
    }

    //Some code

    private void TimerConnectionThreadFinished(object stateInfo)
    {
        Connect();
    }
    #endregion

而且效果很好!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23231466

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档