Console.ReadLine()阻止进程输出

时间:2017-01-23 14:45:42

标签: c# async-await task-parallel-library console-application

是否有更好的方法可以在控制台应用程序中取消长时间运行的任务?此代码已简化,但与我的大型应用程序具有相同的问题。第一种方法Test1()在阻止时只需要3秒,但我希望能够取消此方法,因为GetStreamFromYoutubeDl方法将是无限期运行的较大Task的一部分。

出于某种原因,问题似乎存在于Console.ReadKey() - 或任何阅读变体 - 与阅读过程输出相冲突的方法。这可以很容易地在Test2()中看到,如果您输入大约30左右的按键,Task将立即打印它的输出。

添加TaskCreationOptions.LongRunning重载也无法解决我的问题。

完整的程序包含

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace Testing
{
    class Program
    {
        static void Main(string[] args)
        {
            // Test 1 runs correctly, takes about 3 seconds
            //Test1();
            // Test 2 takes anywhere from 9 - 30 seconds, or hangs forever
            Test2();
        }

        static void Test()
        {
            var stopwatch = new Stopwatch();

            // This blocks, which makes it run correctly
            Task.Factory.StartNew(() => GetStreamFromYoutubeDl()).GetAwaiter().GetResult();

            Console.ReadLine();
        }

        static void Test2()
        {
            var cts = new CancellationTokenSource();

            var stopwatch = new Stopwatch();

            Task.Factory.StartNew(() => GetStreamFromYoutubeDl());

            Console.WriteLine("Press 'q' to exit.");
            while (true)
            {
                // Console.ReadKey here conflicts with the Process.StandardOutput.ReadLine for some reason, can confirm this
                // is the case as if you spam inputting keys, the process will output after ~30 or so key presses
                var read = Console.ReadKey(true);
                if (read.Key == ConsoleKey.Q)
                {
                    cts.Cancel();
                    break;
                }
            }
        }

        static void GetStreamFromYoutubeDl()
        {
            var stopwatch = new Stopwatch();
            var url = "https://www.youtube.com/watch?v=XbE1dL0iNkI";
            var youtubeDl = new ProcessStartInfo
            {
                FileName = "youtube-dl",
                // 
                Arguments = $"{url} -g -f bestaudio --audio-quality 0",
                RedirectStandardOutput = true,
                RedirectStandardError = false,
                CreateNoWindow = true,
                UseShellExecute = false
            };

            stopwatch.Start();
            var p = Process.Start(youtubeDl);

            if (youtubeDl == null)
            {
                Console.WriteLine("Unable to create youtube-dl process");
                return;
            }

            url = p.StandardOutput.ReadLine();

            stopwatch.Stop();
            Console.WriteLine(url + " " + stopwatch.Elapsed);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

根据您的示例:

static void Test3()
{
    var cts = new CancellationTokenSource();
    var processingTask = Task.Factory.StartNew(() => GetStreamFromYoutubeDl(),cts.Token);
    var readingFromConsoleTask = Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Press 'q' to exit.");
        while (true)
        {
            var read = Console.ReadKey(true);
            if (read.Key == ConsoleKey.Q)
            {
                cts.Cancel();
                return;
            }
        }
    });

    Task.WaitAny(processingTask, readingFromConsoleTask);
}

一旦发生以下任何一种情况,执行就会停止:处理任务完成或用户将按“ q”退出。

相关问题