请帮我找到合适的解决方案。 程序等待完成通过控制台,同时监控任务的主要问题。
我写了一些原型,但我不确定它是否有效 - 在这种方法中,我们花费额外的线程等待来自控制台的操作。我没有看到替代方案,因为Console不支持异步(某种 Console.ReadLineAsync )。
更新: 我有两个工作任务( task1,task2 )。他们模拟一些实际工作。 该程序是一个控制台。因此,我们需要让用户有机会停止该程序。默认情况下,通过按“Enter”(通过 consoleTask )的期望来完成此操作。
问题是。如何等待用户完成工作线程和监视停止命令。
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
}
答案 0 :(得分:2)
您应该遵循一些指导原则:
ContinueWith
。请改用await
。Task.Factory.StartNew
。请改用Task.Run
。Main
调用MainAsync
并等待返回的任务。对于大多数应用程序来说,这是您应该使用的唯一阻止。我不确定how to avoid this closuring?
的含义。
对于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();
}
答案 1 :(得分:1)
由于控制台没有SynchronizationContext,因此在执行异步操作时,如果不阻塞主线程,就无法做到这一点。
但是,如果您只是将代码编写为异步并以最简单的方式阻塞,则会更简单。我建议将所有代码移到异步MainAsync
并阻止一次:
static void Main()
{
MainAsync().Wait();
}
static async Task MainAsync()
{
// manage tasks asynchronously
}
您可以使用自定义上下文来执行Stephen Cleary's AsyncContext
之类的异步操作,而不是阻塞。这样可以避免在Task
上同步阻止:
static void Main()
{
AsyncContext.Run(MainAsync);
}