[英]Console.ReadKey vs Console.ReadLine with a Timer
The following code is a well known example to show the difference between a debug and release build: 以下代码是一个众所周知的示例,用于显示调试版本和发布版本之间的区别:
using System;
using System.Threading;
public static class Program
{
public static void Main()
{
Timer t = new Timer(TimerCallback, null, 0, 2000);
Console.ReadLine();
}
private static void TimerCallback(Object o)
{
Console.WriteLine("In TimerCallback: " + DateTime.Now);
GC.Collect();
}
}
If you run this with a debug configuration, the timer will output the current time every two seconds. 如果使用调试配置运行此命令,则计时器将每两秒输出当前时间。 The GC.Collect
doesn't have any effect because the compiler artificially extends the life of the Timer t
variable. GC.Collect
没有任何影响,因为编译器人为地延长了Timer t
变量的寿命。 In a release configuration, the timer will execute only once. 在发布配置中,计时器只执行一次。 The GC.Collect
will garbage collect the t
variable and that's it. GC.Collect
将垃圾收集t
变量,就是这样。
This all works like it should. 一切都像它应该的那样。 The strange thing is, when you change the line Console.ReadLine to Console.ReadKey both configurations run the timer every two seconds. 奇怪的是,当您将Console.ReadLine行更改为Console.ReadKey时, 两个配置每两秒运行一次计时器。
What is the difference between Console.ReadKey and Console.ReadLine? Console.ReadKey和Console.ReadLine有什么区别? I understood from the documentation that Console.ReadKey blocks the thread issuing the ReadKey method. 我从文档中了解到Console.ReadKey阻塞了发出ReadKey方法的线程。 But the GC.Collect still fires.. 但是GC.Collect仍然会发射..
Why is the lifetime of Timer t
extended by blocking the main thread? 为什么通过阻塞主线程来延长Timer t
的生命周期?
When using .NET 3.5, this behavior won't occur! 使用.NET 3.5时,不会发生此行为!
The Console.ReadKey()
method locks the Console.InternalSyncObject
whereas the Console.ReadLine()
method does not. Console.ReadKey()
方法锁定Console.InternalSyncObject
而Console.ReadLine()
方法则不锁定。 When the TimerCallBack()
method tries to write to the Console
the Thread
waits because the Console.InternalSyncObject
is still locked. 当TimerCallBack()
方法尝试写入Console
, Thread
等待,因为Console.InternalSyncObject
仍然被锁定。 Therefore GC.Collect()
is never called. 因此从不调用GC.Collect()
。 As soon as you hit a key the lock is released and GC.Collect()
is called. 只要按下某个键,就会释放锁定并GC.Collect()
。
I changed your code to the following which doesn't lock the Console.InternalSyncObject
and it only beeps once in Release and every 2 seconds in Debug. 我将您的代码更改为以下内容,该代码不会锁定Console.InternalSyncObject
,它只在Release中发出一次哔声,在Debug中每2秒发出一次。
private static void TimerCallback(Object o)
{
Console.Beep();
GC.Collect();
}
The reason the Console.WriteLine() waits is because it tries to acquire a lock on the Console.InternalSyncObject
when creating the Console.Out
TextWriter
for the first time. Console.WriteLine()等待的原因是它在第一次创建Console.Out
TextWriter
时尝试获取Console.InternalSyncObject
上的锁。
Changing your code to the following works as expected as we create the Console.Out
TextWriter
before starting the timer. 在我们在启动计时器之前创建Console.Out
TextWriter
,将代码更改为以下代码可以正常工作。
public static void Main()
{
Console.WriteLine("Loaded");
Timer t = new Timer(TimerCallback, null, 0, 2000);
Console.ReadKey();
}
private static void TimerCallback(Object o)
{
Console.WriteLine("In TimerCallback: " + DateTime.Now);
GC.Collect();
}
This is due to a change in .NET 4.5. 这是由于.NET 4.5的变化。 More info here 更多信息在这里
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.