Как ждать завершения задачи? - PullRequest
0 голосов
/ 05 июня 2019

Проблема с выводом

Токовый выход

работа в ожидании

начало работы

Задержка началась

работа сделана

Задержка закончилась

Где, как я хотел быть

работа в ожидании

начало работы

Задержка началась

Задержка закончилась

работа выполнена

    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 ]

1 голос
/ 05 июня 2019

причина, по которой я сделал это, потому что мне нужно создать задачу в определенный момент времени, но запустить ее позже

Подходящим инструментом в этом случае является Func<Task>, а не конструктор Task. Конструктор Task никогда и никогда не должен использоваться .

В этом случае ваши выходные данные не соответствуют желаемым, поскольку конструктор Task не понимает делегатов async. Таким образом, делегат async, передаваемый конструктору Task, обрабатывается как async void, что делает ожидание его невозможным.

Исправление заключается в использовании async -осведомленных инструментов. В этом случае асинхронно-совместимый делегат . Поскольку объект 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
}
0 голосов
/ 05 июня 2019

Одним из решений является синхронизация основной части задачи. Другими словами, вместо этого:

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

... сделать это:

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

Если вы хотите сохранить его асинхронным, вы должны найти способ дождаться основной части задачи. Это может быть достигнуто путем создания Task<Task> и ожидания результата задачи вместо самой основной задачи:

_task = new Task<Task>(async () => { await Pause(); });
//...
await _task.Result;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...