ASP.NET c#中System.Threading.Timer和Thread.Sleep()的区别

4

可能是重复问题:
使用Thread.Sleep和Timer进行延迟执行的比较

我在考虑在我的ASP.NET Web应用程序中使用System.Threading.Timer还是Thread.Sleep。我查找了它们之间的区别。周期或Sleep将为100ms。 据我所知,如果我使用计时器,它不会阻塞运行线程,但是Sleep会阻塞运行线程。

由于间隔非常小,选择Thread.Sleep(150)是否更好?

编辑:我倾向于像定时器一样在非线程池线程上使用它。我知道计时器将在线程池上运行,但我不想为这样的操作保留线程池线程


这真的取决于情况! - Stefan
2
取决于你想要实现什么。如果你需要运行的线程等待某些准备工作完成,可以使用 Sleep。如果你想要按指定间隔安排方法运行,可以使用 Timer。 - MrKiane
为什么你有其他选择时还要让运行的线程休眠? - Jahan Zinedine
你好Mehmet。请查看此前的问题和答案,特别是由@EricRosenberger提供的答案,因为我认为它回答了你的问题。https://dev59.com/hHRC5IYBdhLWcg3wKtv2 - Dr. Andrew Burnett-Thompson
我想让我的方法永远运行下去(无限期)。并且它必须经常检查某些条件(100毫秒间隔)。我正在考虑如何利用CPU使用率。也许创建自己的线程而不是使用线程池线程并在该线程上休眠会更好? - Mehmet
3个回答

5

我建议阅读:

比较.NET Framework类库中的定时器类

所有的定时器都不会阻塞运行线程,但它们在应用程序主线程上的活动导致它们触发的频率有所不同,如上述文章所述。

你使用哪个取决于你想要的最终结果!尽管Thread.Sleep被大多数人视为反模式。


+1 for Thread.Sleep 是一种反模式。我倾向于仅在测试中使用它来模拟“长时间等待”。 - Dr. Andrew Burnett-Thompson
我可能理解为什么Thread.Sleep是一种反模式,但如果我倾向于在非线程池线程上使用它作为计时器呢?我知道计时器将在线程池上运行,但我不想为这样的操作保留线程池线程。 - Mehmet
1
@Mehmet说你的Thread.Sleep暂停了150毫秒,但代码的执行时间在1毫秒到100毫秒之间变化,那么你的计时器间隔就会在151-251毫秒之间变化,即不准确。使用Timer实现,你可以保证尽可能接近150毫秒的事件触发,无论计时器执行方法需要多长时间。 - Dr. Andrew Burnett-Thompson
1
@Dr.AndrewBurnett-Thompson - 不总是需要或希望精确的时间间隔。规范可能会说,“为了减少服务器负载,收到服务器回复后必须等待至少2秒才能再次轮询服务器”。此外,在代码嵌套数层深时使用计时器回调可能很麻烦。坚持使用计时器可能会将简单的sleep()转变为复杂的状态引擎,必须将其提交为状态对象,并稍后处理超时。不适当地使用计时器与误用sleep()一样都是反模式。 - Martin James
@MartinJames 当然,选择正确的工具很重要。不过现在问题不是很明确,但如果你看一下他之前的问题,他似乎需要每100毫秒轮询聊天应用程序中的传入消息,并且存在CPU峰值问题(可能是由于线程创建),所以这不仅仅是一次性等待。 - Dr. Andrew Burnett-Thompson

3

Thread.Sleep()有一些必不可少的用途。这些情况很少,如果你使用的参数大于约1,那么几乎肯定不是这种情况。

如果可能使用计时器,那么你肯定不需要使用Thread.Sleep()。当有更好的选择时,不要阻塞一个完美的线程。

请注意,计时器在前一个触发器仍在运行时被触发的情况。根据操作的性质,您将想要执行以下操作之一:

  1. 忽略此操作,如果调用的代码对多个同时调用是安全的,则可能没有问题。当然,您必须确信它是安全的。
  2. 锁定计时器触发的操作。请注意,您可能会得到许多待处理操作的队列。
  3. 锁定计时器触发的操作,尝试以零超时获取锁定,如果失败则跳过 - 上次还有一个线程在这里。
  4. 将计时器设置为一次性计时器,在每次调用结束时重新启动。

谢谢。我在回调函数的开头使用了Monitor.TryEnter(LockerObject)。我希望它能处理您的第三种情况(尝试使用零超时获取锁...)。但是我没有应用您的第四种情况,每次调用结束时重新启动计时器是否如此重要? - Mehmet
1
Thread.Sleep()有一些非常有用的用途。这些在某些类型的应用程序中更为常见,例如通信和进程控制。如果您使用的参数小于约2,那么您可能会误用sleep()循环作为线程间通信机制 - 这会引入资源浪费和延迟。如果线程需要10秒的延迟,则sleep(10000)几乎是最简单的方法。 - Martin James
1
Mehmet。您只需要采用以下其中一种方法,尽管您想使用具有显式超时的TryEnter形式if(!Monitor.TryEnter(LockerObject, 0))return;。请注意,在finally中调用Exit,除非您希望计时器方法在可能存在损坏数据的情况下停止工作。@MartinJames是的,另一个常见情况是由高级代码使用的低级线程代码,例如此类代码。 - Jon Hanna

2
请查看以前的问题和答案,特别是由@EricRosenberger提供的答案,我相信它回答了你的问题。
关于你的情况,我相信你是在问与你之前提出的这个问题有关的事情?也就是说:你有一个使用线程的ASP.NET应用程序,CPU使用率会飙升,但使用Systen.Threading.Timer时不会。这可能与当前问题无关,但为了帮助你整体解决问题,你可能会发现像Eric Rosenberger所说的那样,线程的创建和销毁可能是导致CPU飙升的原因,而不是在线程内运行的代码实现。
最好的问候。

当你只能通过研究同一用户的其他问题来给出一个好的答案时,这有点令人恼火! - ColinE
@ColinE 抱歉意识到在不同线程之间交叉污染是一团糟,但我之前已经回答了Mehmet的其他问题,所以对此很熟悉。并不是我有那么多闲暇时间去寻找!!:p - Dr. Andrew Burnett-Thompson
谢谢,我已经阅读了那个帖子,但它并没有回答我的具体问题。 - Mehmet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接