如何等待任务完成?

时间:2019-06-05 08:32:35

标签: c# .net task-parallel-library

问题出在输出

当前输出为

  

等待工作

     

工作开始

     

延迟开始

     

工作完成

     

延迟结束

想去哪里

  

等待工作

     

工作开始

     

延迟开始

     

延迟结束

     

工作完成

    private static Task _task;

    public static  void Main(string[] args)
    {

        Call().Wait();
    }

    private static async Task Call()
    {
        _task = new Task(async () => { await Pause(); });
        var timer = new Timer();
        timer.Interval = 10000;
        timer.Enabled = true;
        timer.AutoReset = false;
        timer.Elapsed += Timer_Elapsed;
        Console.WriteLine("job waiting");
        await _task;
        Console.WriteLine("job done");
        Console.ReadKey();
    }

    public static async Task Pause()
    {
        Console.WriteLine("Delay started");
        await Task.Delay(10000);
        Console.WriteLine("Delay ended");

    }
    private static void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        Console.WriteLine("job starting");

        _task.Start();

    }

2 个答案:

答案 0 :(得分:1)

  

之所以这样做,是因为我需要在某个时间点创建一个任务,但稍后再开始

在这种情况下,合适的工具是Func<Task>,而不是Task构造函数。 The Task constructor should never, ever be used

在这种情况下,由于Task构造函数无法理解async委托,因此您的输出不理想。因此,传递给async构造函数的Task委托被视为async void,这使得等待它变得不可行。

解决方法是使用支持async的工具。在这种情况下,为async-compatible delegate。由于Task对象在计时器事件触发之前不存在,因此您还需要将该对象作为“信号”传递给另一个方法,这有点尴尬。大多数现实世界的代码都不需要这样做:

private static Func<Task> _func;
private static TaskCompletionSource<Task> _taskSignal = new TaskCompletionSource<Task>();
private static async Task Call()
{
  _func = Pause;
  var timer = new Timer();
  timer.Interval = 10000;
  timer.Enabled = true;
  timer.AutoReset = false;
  timer.Elapsed += Timer_Elapsed;
  Console.WriteLine("job waiting");
  var task = await _taskSignal.Task; // Get the Task instance representing Pause
  await task; // Wait for Pause to finish
  Console.WriteLine("job done");
  Console.ReadKey();
}

public static async Task Pause()
{
  Console.WriteLine("Delay started");
  await Task.Delay(10000);
  Console.WriteLine("Delay ended");
}

private static void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
  Console.WriteLine("job starting");
  var task = _func(); // Start Pause running
  _taskSignal.TrySetResult(task); // Pass the Pause task back to Main
}

答案 1 :(得分:-1)

一种解决方案是使任务主体同步。换句话说:

_task = new Task(async () => { await Pause(); });

...执行此操作:

_task = new Task(() => { Pause().Wait(); });

如果要使其保持异步,则必须找到一种方法来等待任务主体。这可以通过创建Task<Task>并等待任务的结果而不是主要任务本身来实现:

_task = new Task<Task>(async () => { await Pause(); });
//...
await _task.Result;