2015-09-18 2 views
0

Я узнал о async/await с C# 4.5 и задаюсь вопросом, что происходит, когда несколько «ждущих» ждут той же задачи.Является ли порядок возобновления нескольких ожидающих выражений одной и той же задаче?

Я экспериментирую, и я думаю, что я понимаю, что происходит. Тем не менее, у меня есть некоторые вопросы, чтобы спросить:

Посмотрите на этот кусок кода:

AsyncAwaitExperiment.fxml.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Threading; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Shapes; 

namespace View 
{ 
    /// <summary> 
    /// Interaction logic for AsyncAwaitExperiment.xaml 
    /// </summary> 
    public partial class AsyncAwaitExperiment : Window 
    { 

     private CancellationTokenSource token; 
     private Task longRunningTask; 

     public AsyncAwaitExperiment() 
     { 
      InitializeComponent(); 
     } 

     private void startAsyncOperation(object sender, RoutedEventArgs e) 
     { 
      if (longRunningTask != null && !longRunningTask.IsCompleted) 
      { 
       return; 
      } 
      else 
      { 
       longRunningTask = null; 
       token = new CancellationTokenSource(); 
      } 

      Action action =() => 
      { 
       while (!token.Token.IsCancellationRequested) 
       { 
        Thread.Sleep(100); 
       } 
      }; 

      longRunningTask = Task.Factory.StartNew(
       action, 
       token.Token, 
       TaskCreationOptions.LongRunning, 
       TaskScheduler.Current); 
     } 

     private void stopOperation(object sender, RoutedEventArgs e) 
     { 
      if (longRunningTask == null 
       || longRunningTask.IsCompleted 
       || token == null 
       || token.Token.IsCancellationRequested) 
      { 
       return; 
      } 
      token.Cancel(); 
     } 

     private async void firstAwait(object sender, RoutedEventArgs e) 
     { 
      if (longRunningTask == null || longRunningTask.IsCompleted) 
       return; 
      await longRunningTask; 
      Console.WriteLine("First Method"); 
     } 

     private async void secondAwait(object sender, RoutedEventArgs e) 
     { 
      if (longRunningTask == null || longRunningTask.IsCompleted) 
       return; 
      await longRunningTask; 
      Console.WriteLine("Second Method"); 
     } 
    } 
} 

AsyncAwaitExperiment.fxml

<Window x:Class="View.AsyncAwaitExperiment" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="AsyncAwaitExperiment" Height="300" Width="300"> 
    <Grid> 
     <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> 
      <Button Content="Start Async" Margin="3" Click="startAsyncOperation" /> 
      <Button Content="Stop Async" Margin="3" Click="stopOperation" /> 
      <Button Content="Await First" Margin="3" Click="firstAwait" /> 
      <Button Content="Await Second" Margin="3" Click="secondAwait" /> 
     </StackPanel> 
    </Grid> 
</Window> 

Поведение этого кода:

  1. Начать асинхронную работу при нажатии кнопки «Пуск».
  2. Остановить асинхронную операцию, когда нажата кнопка «Остановить» .
  3. Когда нажата кнопка «Первая ожидание», дождитесь завершения задачи , а затем распечатайте что-то на консоли.
  4. То же самое со второй кнопкой («второй ждут»).

С помощью этой части кода и некоторых точек разрыва я заметил некоторые виды поведения.

  1. Когда я жду задания, он возобновит код в точке, которая была остановлена ​​ранее . Наверное, ничего нового здесь.
  2. Если (это интересная часть), у меня есть более одного «awaiter» для той же задачи, она возобновится в том же порядке ожидаемого кода. EX: если сначала щелкнул firstAwait, а второй - второй, , когда задача завершается, и возобновление потока кода будет следовать за в том же порядке: сначала дождитесь, а затем еще раз.

Вопросы:

  1. Есть ли гарантия такого поведения (о порядке резюме)?
  2. Есть ли проблемы при использовании этого планировщика (TaskScheduler.Current) ?
  3. Могу ли я повторно использовать токен отмены или мне действительно нужно создать один каждый раз, когда я отменяю и запускаю задачу?

PS: Извините за мой плохой английский:/

+0

Я не думаю, что это гарантировано, и я бы не хотел * предполагать, что это было так, а затем сломано код позже. Если есть какая-то другая зависимость между фрагментами кода (например, для того, чтобы вы хотели получить конкретный заказ), почему бы не сделать его явным? –

+0

Множественные ожидания - это * не * типичный сценарий - в таком надуманном случае я бы не сделал * никаких * предположений о том, что может или не может произойти. Кроме того, вы используете 'async void', который заставляет асинхронные методы в основном запускать и забывать. Ваше приложение может завершиться до завершения этих методов. В любом случае возобновление от 'ожидания 'может происходить в любом потоке, на любом ядре. –

+0

@Damien_The_Unbeliever в этом случае нет необходимости в конкретном заказе. Я сомневаюсь в поведении, только это. –

ответ

2

Вы не должны считать ничего о порядке, в котором будет возобновить деятельность.Предположим, что в будущем кому-то удалось написать новую систему пользовательского интерфейса, которая была полностью многопоточной, вы ожидали бы, что даже потоки пользовательского интерфейса будут выполняться параллельно (Примечания: Никто не считает, что разумно писать многопоточную систему пользовательского интерфейса в настоящее время, даже если две задачи возобновляются «в одно и то же время», один из них может быть приостановлен на неопределенный срок)

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

И, наконец, нет. После того, как вы использовали CancellationToken, все сделано. Если вам нужен другой, вам нужно создать новый. Это фактически заставляет задуматься о нескольких задачах/действиях, о которых проще думать - ни один токен не может быть отменен, чтобы быть отложенным.

+0

«один из них может быть бесконечно приостановлен», подождите паузу в потоке? –

+0

А как насчет «TaskScheduler.Current», хорошо ли использовать его таким образом? –

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