我想以不同的时间间隔执行方法,并且正在考虑使用Timer类来安排此时间。但是,我想了解一下Timer是否为每个新时间表启动了一个新线程,这可能会影响应用程序的性能
答案 0 :(得分:4)
System.Threading.Timer
:简答:90%的时间:否。它使用线程池获取现有线程(没有做任何事情)。
长答案:可能!如果池中的所有线程都忙,则操作系统需要创建一个新线程并将其添加到池中,然后由计时器使用。
https://docs.microsoft.com/en-us/dotnet/api/system.threading.timer?view=netframework-4.8
提供了一种机制,用于以指定的时间间隔在线程池线程上执行方法。此类不能继承。
System.Windows.Forms.Timer
触发新的Win32窗口消息,该消息将按设置的时间间隔发送到Form
。它不使用专用线程也不使用池线程,而是使用Win32的SetTimer
函数。
System.Timers.Timer
默认情况下还将使用池线程(就像System.Threading.Timer
一样),但可以执行线程同步。参见https://docs.microsoft.com/en-us/dotnet/api/system.timers.timer?view=netframework-4.8
我建议您改用await Task.Delay
-因为它不会导致使用新线程(记住Task
不是线程)-尽管如果您确实使用{{1 }}在池线程中运行协程,然后它可能会在新线程上运行:
Task.Run
答案 1 :(得分:2)
Dai很好地回答了有关计时器和线程的问题。
我想我会给你一种替代的方式来编写代码。您应该使用Microsoft的Reactive Framework(又名Rx)-NuGet System.Reactive
并添加using System.Reactive.Linq;
-然后,您可以这样做:
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
EventLoopScheduler els = new EventLoopScheduler();
els.Schedule(() => Console.WriteLine(Thread.CurrentThread.ManagedThreadId));
IObservable<string> pings = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(30), els).Select(x => "Ping!");
IObservable<string> pongs = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(20), els).Select(x => "Pong!");
IObservable<string> pangs = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(10), els).Select(x => "Pang!");
IObservable<string> query = Observable.Merge(els, pings, pongs, pangs);
IDisposable subscription = query.Subscribe(x => Console.WriteLine($"{x} ({Thread.CurrentThread.ManagedThreadId})"));
Console.ReadLine();
subscription.Dispose();
els.Dispose();
EventLoopScheduler
创建一个可重复使用的专用线程,直到您在其上调用.Dispose()
为止。
Observable.Timer
和Observable.Merge
都允许您指定要使用EventLoopScheduler
来确保代码在该线程上运行。