2016-03-03 5 views
-2

Скажем, у меня есть две задачи, с учетом следующих требований:Подождите только одна задача завершить

  1. Оба являются асинхронными.
  2. Оба запускаются параллельно
  3. В тот момент, когда один из них завершается, мне нужно знать, что он сделал.

Я придумал следующий код, но он просто зависает после запуска обеих задач (функция WaitAny никогда не возвращается). Я также получаю squiggly строку под функцией Run, говорящей мне добавить ожидание внутри него, но VS жалуется, когда я пытаюсь добавить его перед Task.WaitAny. Должен ли я обернуть WaitAny в другую задачу? Что я делаю не так?

async void Run() 
{ 
    Task task1 = Task1(); 
    Task task2 = Task2(); 

    int completedTaskIdx = Task.WaitAny(task1, task2); 

    Debug.WriteLine("completedTaskIdx = {0}", completedTaskIdx.ToString()); 
} 

async Task Task1() 
{ 
    Debug.WriteLine("Task 1 Start"); 
    await Task.Delay(5000); 
    Debug.WriteLine("Task 1 Stop"); 
} 

async Task Task2() 
{ 
    Debug.WriteLine("Task 2 Start"); 
    await Task.Delay(10000); 
    Debug.WriteLine("Task 2 Stop"); 
} 
+1

try ** WhenAny ** – Eser

+0

@Eser Я действительно посмотрел на него, но он не возвращает индекс завершенной задачи. – Eternal21

+0

@ Eternal21 Ваше требование 3. не говорило, что вам нужно знать индекс завершенной задачи, только какие задачи были выполнены. Он делает это, возвращая завершенную задачу. –

ответ

5

Не блокируйте нить пользовательского интерфейса при использовании asnyc/wait, you will cause dedlocks. Ваш WaitAny() заставляет зайти в тупик. Вместо этого используйте WhenAny, вы можете использовать Array.IndexOf( для перевода возвращенной задачи обратно в индекс.

async Task Run() 
{ 
    Task task1 = Task1(); 
    Task task2 = Task2(); 

    var tasks = new[] {task1, task2}; 
    Task completedTask = await Task.WhenAny(tasks); 

    //It is a good idea to await the retuned task, this is the point a execption would 
    //be raised if the task finished with a exception. 
    await completedTask; 

    int completedTaskIdx = Array.IndexOf(tasks, completedTask); 

    //.ToString() will cause you to have a bug, you are calling the 
    //wrong overload of WriteLine. The correct overload will call .ToString() for you. 
    Debug.WriteLine("completedTaskIdx = {0}", completedTaskIdx); 
} 

Я также исправлена ​​ошибка в вашем Debug.WriteLine( вызова, вы где вызова this overload, когда вы хотели this overload. Я также заменил ваш async void на async Task, you should never do asnyc void, если вы не используете его в соответствии с сигнатурой обработчика события.

+0

Никогда не знал об этой перегрузке WriteLine - хорошо знать. Я только что начал явно указывать ToString() в моих параметрах формата, потому что я где-то читал, что он предотвращает ненужный бокс/unboxing. – Eternal21

+0

@ Eternal21 Я бы только беспокоился об этом, если вы обнаружите измеримую проблему с производительностью. –

Смежные вопросы