【问题标题】:Why awaiting cold Task does not throw为什么等待冷任务不抛出
【发布时间】:2014-08-05 21:34:24
【问题描述】:

我只是在尝试看看当等待一个冷任务(即尚未启动的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 中或在Task.Run 返回的任务上调用Wait()Result 会在主控制台线程上引发异常。

【问题讨论】:

    标签: c# asynchronous async-await


    【解决方案1】:

    您正在尝试启动异步方法返回的任务 - 不是您开始时的冷任务。实际上,如果您在 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 是在模拟要在其他任务中完成的实际工作。

    至于为什么等待未开始的任务不会引发异常 - 老实说,我认为这是合理的。它允许上述情况有效,这在某些情况下可能会使生活更轻松。 (例如,您可能会在开始之前创建很多任务 - 并且您可能希望在开始之前等待它们完成。)

    【讨论】:

    • 谢谢乔恩,我想我有点纠结
    【解决方案2】:

    有谁知道是否有办法在完成一项冷任务后启动它 正在等待?

    你仍然可以从 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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-08-14
      • 1970-01-01
      • 2018-07-07
      • 1970-01-01
      • 2020-01-02
      • 1970-01-01
      • 2020-04-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多