【发布时间】:2019-08-04 20:05:16
【问题描述】:
我想以不同的时间间隔执行方法,并且正在考虑使用 Timer 类来安排这个。但是,我想了解 Timer 是否为每个新计划启动了一个新线程,这可能会影响应用程序的性能
【问题讨论】:
标签: c# .net multithreading
我想以不同的时间间隔执行方法,并且正在考虑使用 Timer 类来安排这个。但是,我想了解 Timer 是否为每个新计划启动了一个新线程,这可能会影响应用程序的性能
【问题讨论】:
标签: c# .net multithreading
System.Threading.Timer:简短回答:90% 的时间:没有。它使用线程池来获取现有线程(不做任何事情)。
长答案:可能!如果池中的所有线程都忙,则操作系统将需要创建一个新线程并将其添加到池中,然后由 Timer 使用。
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 - 因为它不会导致使用新线程(请记住Tasks 不是线程) - 尽管如果您确实使用Task.Run 来运行协程在池线程中然后它可以在新线程上运行:
public static class Foo
{
public static async Task<Int32> Main( String[] args )
{
Task loop30 = this.Every30Seconds();
Task loop20 = this.Every20Seconds();
Taks loop10 = this.Every10Seconds();
await Task.WhenAll( loop30, loop20, loop10 );
return 0;
}
public static async Task Every30Seconds()
{
while( true )
{
Console.WriteLine("Ping!");
await Task.Delay( 30 * 1000 );
}
}
public static async Task Every20Seconds()
{
while( true )
{
Console.WriteLine("Pong!");
await Task.Delay( 20 * 1000 );
}
}
public static async Task Every10Seconds()
{
while( true )
{
Console.WriteLine("Pang!");
await Task.Delay( 10 * 1000 );
}
}
}
【讨论】:
Dai 很好地回答了有关计时器和线程的问题。
我想我会给你另一种编写代码的方法。您应该使用 Microsoft 的反应式框架(又名 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 来确保代码在该线程上运行。
【讨论】: