我只是在尝试查看当等待冷任务(即尚未启动的Task
)时会发生什么。令我惊讶的是,代码只是永远挂起而且“Finsihed ”永远不会被打印出来。我希望抛出异常。
public async Task Test1()
{
var task = new Task(() => Thread.Sleep(1000));
//task.Start();
await task;
}
void Main()
{
Test1().Wait();
Console.WriteLine("Finished");
}
然后我可能会从另一个线程启动任务,所以我将代码更改为:
public async Task Test1()
{
var task = new Task(() => Thread.Sleep(1000));
//task.Start();
await task;
Console.WriteLine("Test1 Finished");
}
void Main()
{
var task1 = Test1();
Task.Run(() =>
{
Task.Delay(5000);
task1.Start();
});
task1.Wait();
Console.WriteLine("Finished");
}
但它仍在task1.Wait()
被屏蔽。有人知道在等待之后是否有办法开始冷却任务?
否则似乎没有必要能够await
执行冷任务,所以也许任务应该在等待时启动或者应该抛出异常。
更新
我正在等待错误的任务,即Test1
返回的外部任务,而不是内部新任务。 @Jon Skeet提到的InvalidOperationException被抛出Task.Run
但是因为没有观察到生成的任务,所以主线程上没有抛出异常。在try/catch
内放Task.Run
或在Wait()
返回的任务上调用Result
或Task.Run
会在主控制台主题上抛出异常。
答案 0 :(得分:14)
您正在尝试启动异步方法返回的任务 - 不是您开始使用的冷任务。实际上,如果您在Task.Run
电话中添加一些诊断信息,您会看到引发异常:
System.InvalidOperationException:可能不会在promise样式的任务上调用Start。
这是一个显示我认为你真正想要做的事情的例子:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Test
{
static void Main(string[] args)
{
// Not using Task.Delay! That would be pointless
Task t1 = new Task(() => Thread.Sleep(1000));
Task t2 = Await(t1);
Console.WriteLine(t2.Status);
Console.WriteLine("Starting original task");
t1.Start();
Console.WriteLine(t2.Status);
t2.Wait();
Console.WriteLine(t2.Status);
}
static async Task Await(Task task)
{
Console.WriteLine("Beginning awaiting");
await task;
Console.WriteLine("Finished awaiting");
}
}
请注意使用Thread.Sleep
代替Task.Delay
;除非您使用Task.Delay
的结果,否则它基本上什么都不做。使用Thread.Sleep
模拟要在其他任务中完成的实际工作。
至于为什么等待未开始的任务不会引发异常 - 我认为这是合理的,说实话。它允许上述情况有效,这在某些情况下可以使生活更轻松。 (例如,您可以在启动它们之前创建许多任务 - 并且您可能希望在启动它们之前等待它们完成。)
答案 1 :(得分:1)
有没有人知道是否有办法在它完成后开始冷任务 正在等待?
您仍然可以使用async
方法创建一个冷任务,并在以后启动它,如果这是您想要的:
class Program
{
public static async Task Test1()
{
await Task.Delay(1000);
Console.WriteLine("Test1 is about to finish");
}
static void Main(string[] args)
{
var taskOuter = new Task<Task>(Test1);
var taskInner = taskOuter.Unwrap();
Task.Run(() =>
{
Thread.Sleep(2000);
// run synchronously
taskOuter.RunSynchronously();
// or schedule
// taskOuter.Start(TaskScheduler.Defaut);
});
taskInner.Wait();
Console.WriteLine("Enter to exit");
Console.ReadLine();
}
}