C# 具有任务控制的异步控制台
请帮我找到正确的解决方案。 主要问题是等待程序通过控制台完成,同时监控任务 我写了一些原型,但我不确定这是否有效——在这种方法中,我们需要额外的线程等待控制台的操作。我看不到替代方案,因为Console不支持某种类型的Console.ReadLineAsync异步 更新: 我有两个工作任务task1和task2。它们模拟了一些真实的工作。 该程序是一个控制台。因此,我们需要给用户一个停止程序的机会。默认情况下,在控制台中,这是通过期望通过控制台任务按Enter键来完成的 问题是。如何等待工作线程完成并监视用户发出的停止命令C# 具有任务控制的异步控制台,c#,.net,asynchronous,console,task-parallel-library,C#,.net,Asynchronous,Console,Task Parallel Library,请帮我找到正确的解决方案。 主要问题是等待程序通过控制台完成,同时监控任务 我写了一些原型,但我不确定这是否有效——在这种方法中,我们需要额外的线程等待控制台的操作。我看不到替代方案,因为Console不支持某种类型的Console.ReadLineAsync异步 更新: 我有两个工作任务task1和task2。它们模拟了一些真实的工作。 该程序是一个控制台。因此,我们需要给用户一个停止程序的机会。默认情况下,在控制台中,这是通过期望通过控制台任务按Enter键来完成的 问题是。如何等待工作线程
static void Main(string[] args)
{
CancellationTokenSource mycts = new CancellationTokenSource();
var task1 = Task.Run(() =>
{
// doing some work, that can throw exception
Thread.Sleep(1000);
// how to avoid this closuring ?
mycts.Token.ThrowIfCancellationRequested();
throw new InvalidOperationException("test");
}).ContinueWith((_) => mycts.Cancel()); // Do I need caching this task?
var task2 = Task.Run(() =>
{
// doing some work, that can throw exception
Thread.Sleep(5000);
// again closuring
mycts.Token.ThrowIfCancellationRequested();
throw new InvalidOperationException("test");
}).ContinueWith((_) => mycts.Cancel()); // Do I need caching this task?
// I do not know how to do better with Console !!
var consoleTask = Task.Factory.StartNew((cts) =>
{
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}, mycts).ContinueWith((_) => mycts.Cancel()); // Do I need caching this task?
// Waiting for the Completion or Exception
Task.WaitAny(task1, task2, consoleTask);
// Now waiting for the completion of workflow
try
{
Task.WaitAll(task1, task2);
}
catch (Exception ex)
{
// log faulted tasks
}
//Exit
}
由于console没有SynchronizationContext,所以在执行异步操作时,如果不阻塞主线程,您将无能为力 但是,如果您只是以异步方式编写代码,并以尽可能简单的方式阻塞代码,则会简单得多。我建议将所有代码移动到async MainAsync并阻塞一次:
static void Main()
{
MainAsync().Wait();
}
static async Task MainAsync()
{
// manage tasks asynchronously
}
您可以做的不是阻塞,而是使用自定义上下文来执行异步操作,如。这样可以避免在任务上同步阻塞:
您应该遵循以下几条准则: 不要使用ContinueWith。使用wait代替。 不要使用Task.Factory.StartNew。使用任务。改为运行。 不要混合使用阻塞代码和异步代码。在控制台应用程序的情况下,通常最好只让Main调用mainsync并等待返回的任务。对于大多数应用程序,这是唯一应该使用的阻塞。 我不知道怎样才能避免这种情况?意味着 对于ReadLine和其他控制台方法,您是正确的,不幸的是没有异步方法。使用单独的线程可能会起作用,但Console类更具体地说,Console输入和输出流有一些不寻常的锁,因此我不确定这是否会起作用:
static void Main(string[] args)
{
MainAsync().Wait();
}
static CancellationTokenSource mycts = new CancellationTokenSource();
static async Task MainAsync()
{
try
{
var task1 = CancelAfterSuccessfulCompletionAsync(
Task.Run(() => SomeWorkThatCanThrowException()));
var task2 = CancelAfterSuccessfulCompletionAsync(
Task.Run(() => OtherWorkThatCanThrowException()));
var consoleTask = CancelAfterSuccessfulCompletionAsync(
Task.Run(() => MonitorConsole()));
await Task.WhenAll(task1, task2, consoleTask);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
static void OtherWorkThatCanThrowException()
{
Thread.Sleep(5000);
mycts.Token.ThrowIfCancellationRequested();
throw new InvalidOperationException("test");
}
static void SomeWorkThatCanThrowException()
{
Thread.Sleep(1000);
mycts.Token.ThrowIfCancellationRequested();
throw new InvalidOperationException("test");
}
static void MonitorConsole()
{
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}
static async Task CancelAfterSuccessfulCompletionAsync(Task task)
{
await task;
mycts.Cancel();
}
这不正是我需要的。我需要以某种方式在控制台中为用户提供一个stop命令,即按Enter键退出。你打算怎么做?我们会在这段代码中结束MyCT吗?如何避免呢?取消标记源mycts;var task1=Task.Run=>{mycts.Token.ThrowIfCancellationRequested;}@你为什么要回避它?我找到了解决闭包问题的方法。在这里,阅读.NET 4.5中“将闭包信息编码到任务的状态对象”一章中的TPL性能改进非常有趣。@SoaperPlus:您不需要这样做。没有问题。你不应该有任务。WaitAlltask1,task2;因为如果WaitAny由于异常而返回,那么您将需要点击enter退出。它会让你疯狂地点击回车键,以防有一个异常被愚蠢地抛出?我希望在异常处理块之后,程序将正确完成。HmmIt将正确完成,但您明确要求转到所有任务的末尾。虽然我没有试过,但它看起来就是这样。我可能错了
static void Main(string[] args)
{
MainAsync().Wait();
}
static CancellationTokenSource mycts = new CancellationTokenSource();
static async Task MainAsync()
{
try
{
var task1 = CancelAfterSuccessfulCompletionAsync(
Task.Run(() => SomeWorkThatCanThrowException()));
var task2 = CancelAfterSuccessfulCompletionAsync(
Task.Run(() => OtherWorkThatCanThrowException()));
var consoleTask = CancelAfterSuccessfulCompletionAsync(
Task.Run(() => MonitorConsole()));
await Task.WhenAll(task1, task2, consoleTask);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
static void OtherWorkThatCanThrowException()
{
Thread.Sleep(5000);
mycts.Token.ThrowIfCancellationRequested();
throw new InvalidOperationException("test");
}
static void SomeWorkThatCanThrowException()
{
Thread.Sleep(1000);
mycts.Token.ThrowIfCancellationRequested();
throw new InvalidOperationException("test");
}
static void MonitorConsole()
{
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}
static async Task CancelAfterSuccessfulCompletionAsync(Task task)
{
await task;
mycts.Cancel();
}