如何阻止控制台暂停我的线程和任务

本文关键字:线程 任务 我的 暂停 何阻止 控制台 | 更新日期: 2023-09-27 18:32:55

当我在控制台窗口中使用滚动条时,所有线程和任务都会暂停。有什么方法可以防止这种情况发生吗?

例:

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 - 方法中等待,直到释放滚动条。

有谁知道如何解决我的问题?

如何阻止控制台暂停我的线程和任务

你无能为力来阻止这种情况。 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(中使用该类。

如果您不希望代码在锁定对控制台的访问时阻止(在本例中为用户),并且不要等待该异步操作完成再继续,则需要异步写入控制台。 这可以像使用 Task.Run(() => Console.WriteLine(z)) 代替 Console.WriteLine(z) 一样简单。

你还需要复制(在调用Run之前)任何闭合变量,这些变量在调用Task.Run后最终会发生变化,因为闭包在变量而不是值上闭合。

也就是说,这强烈表明您应该在这里重新考虑您的设计。 也许控制台不是您输出数据的正确方式;另一种类型的 UI 可能是合适的。