首页 > 解决方案 > 保持控制台打开而不中断其他功能

问题描述

即使所有等待项都已完成,如何保持控制台应用程序打开,但不会中断其他可能的等待项?

我知道我的问题听起来很奇怪,但只是为了解释一下:

我正在使用 Telegram.Bot 库,我需要收听来自电报的所有传入更新。问题是,一旦我设置了更新处理程序,控制台就会关闭。

我的另一件事是使用 RestSharp 的请求,该请求每 x 分钟从 API 获取一个 json,这可以完成使控制台保持活动状态的工作,因为我正在使用一种方法来在中断循环之前检测控制台取消。

还有另一种更好的方法来做我想做的事吗?

这就是我用于控制台近距离监听的内容https://stackoverflow.com/a/22996661/12420972

我将 exitSystem 作为 while 循环的变量

while (!exitSystem)
     // Do this

标签: c#async-await

解决方案


使用 while 循环将不必要地浪费 CPU 周期,因为您要做的就是等待退出信号。您可以使用TaskCompletionSource. 下面的代码让您了解如何实现它。

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

namespace ConsoleApp
{
    public class Program
    {
        private static readonly TaskCompletionSource<object> TaskCompletionSrc = new TaskCompletionSource<object>();
        static async Task<int> Main(string[] args)
        {
            Console.WriteLine("Launching background tasks...");
            var thread = new Thread(DoSomethingInBackground);
            thread.Start();

            //wait for the task completion event
            await TaskCompletionSrc.Task;

            Console.WriteLine("Task completed. Exiting...");
            return 0;
        }

        private static void DoSomethingInBackground()
        {
            Thread.Sleep(5000);
            //signal that task has completed
            TaskCompletionSrc.SetResult(null);
        }
    }
}

更新答案:

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

namespace ConsoleApp
{
    public class Program
    {
        //API call interval in milliseconds
        private const int ApiCallIntervalMilliSeconds = 5000;
        public static void Main(string[] args)
        {

            //create token source for cancelling the background operations when the main thread exists
            using (var cancellationTokenSrc = new CancellationTokenSource())
            //create timer which triggers the MakeApiCallback immediately and repeats for every specified milliseconds
            using (var timer = new Timer(TriggerApiCall, cancellationTokenSrc, TimeSpan.Zero,
                TimeSpan.FromMilliseconds(ApiCallIntervalMilliSeconds)))
            {
                Console.WriteLine("Program is running. Press any to exit...");

                //blocks the main thread from running to completion
                Console.Read();

                //key press, cancel any API calls in progress
                cancellationTokenSrc.Cancel();
            }

        }

        public static async void TriggerApiCall(object argument)
        {
            var tokenSrc = (CancellationTokenSource) argument;
            await MakeApiCall(tokenSrc.Token);
        }


        private static async Task MakeApiCall(CancellationToken cancellationToken)
        {
            Console.WriteLine("API Call in progress...");
            try
            {
                //simulate the background work
                await Task.Delay(3000, cancellationToken);
            }
            catch (TaskCanceledException)
            {
                Console.WriteLine("API call cancelled!");
                return;
            }
            catch(Exception ex)
            {
                Console.WriteLine("API call failed. Exception:" + ex);
                return;
            }

            Console.WriteLine("API call completed successfully.");
        }
    }
}

推荐阅读