当我在控制台窗口中使用滚动条时,所有线程和任务都会暂停。有没有办法防止这种情况发生?
示例:
Task.Run(async () =>
{
for (var z = 0; true; z++)
{
Console.WriteLine(z);
await Task.Delay(200);
}
});
或
var s = new Thread(() =>
{
for (var z = 0; true; z++)
{
Console.WriteLine(z);
Thread.Sleep(200);
}
});
如果您将这些代码示例中的任何一个作为控制台应用程序运行,则两者都将执行相同的操作:打印一些数字。执行期间,用鼠标左键按住滚动条一段时间,数字将停止显示。任务/线程已暂停。当您松开鼠标按钮时,数字将继续。
因为滚动条释放后的数字跟在之前的数字之后,控制台并没有简单地停止输出数字。它一直在Console.WriteLine中等待 - 直到释放滚动条。
有谁知道如何解决我的问题?
答案 0 :(得分:3)
你无能为力阻止这一切。在按住滚动条时,Console.WriteLine
将阻塞,这与线程或任务完全无关。以下小程序显示了同样的问题。
using System;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
for (var z = 0; true; z++)
{
Console.WriteLine(z);
Thread.Sleep(200);
}
}
}
}
你不能改变Console.WriteLine
的行为你唯一可以做的就是在你和控制台的写入之间放一个缓冲区。
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
//The writer lives in another thread.
var s = new Thread(ConsoleWriter);
s.Start();
for (var z = 0; true; z++)
{
//This add call does not get blocked when Console.WriteLine gets blocked.
LinesToWrite.Add(z.ToString());
Thread.Sleep(200);
}
}
static void ConsoleWriter()
{
foreach (var line in LinesToWrite.GetConsumingEnumerable())
{
//This will get blocked while you hold down the scroll bar but
// when you let go it will quickly catch up.
Console.WriteLine(line);
}
}
static readonly BlockingCollection<string> LinesToWrite = new BlockingCollection<string>();
}
}
这只是一个快速而又肮脏的解决方案,还有其他方法可以解决这个问题,使其更加透明,就像创建一个派生自TextWriter
的类一样,它将缓冲调用并在调用时使用该类Console.SetOut(
答案 1 :(得分:0)
如果您不希望代码在访问控制台时被阻止(在这种情况下是用户),则需要异步写入控制台,而不是等待异步操作完成之前继续。这可以像使用Task.Run(() => Console.WriteLine(z))
代替Console.WriteLine(z)
一样简单地完成。
您还需要复制(在调用Run
之前)任何已关闭的变量,这些变量在调用Task.Run
后最终会被变异,因为闭包会关闭变量而不是变量而不是价值观。
那就是说,这是一个强有力的迹象,你应该在这里重新考虑你的设计。也许控制台不是输出数据的正确方法;另一种类型的UI可能是合适的。