【问题标题】:How to stop the Console from pausing my Threads and Tasks?如何阻止控制台暂停我的线程和任务?
【发布时间】:2014-12-02 21:34:32
【问题描述】:

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

示例:

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

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

【问题讨论】:

  • 您的程序只是因为您阻止了输出而暂停。 IE。如果程序没有调用,例如Console.WriteLine(),它会一直运行得很好。事实上,任何试图写入输出(stdout 或 stderr)的线程都将继续运行。所以,要么不要阻塞输出,要么运行重要的东西而不写入输出。

标签: c# multithreading console


【解决方案1】:

要阻止这种情况,您无能为力。 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 的类,该类将缓冲调用并在调用 @987654321 时使用该类@。

【讨论】:

    【解决方案2】:

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

    您还需要复制(在调用Run 之前)任何在调用Task.Run 之后最终会发生突变的封闭变量,因为闭包是封闭变量而不是值。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-22
      • 2019-08-09
      • 2020-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多