2010-10-30 3 views
81

Может ли кто-нибудь объяснить, что делает функция await?Какая новая функция ожидания C#?

+1

Это вы имеете в виду? [Асинхронное программирование в C# 5.0 часть вторая: откуда ждать?] (Http://blogs.msdn.com/b/ericlippert/archive/2010/10/29/asynchronous-programming-in-c-5-0-part- two-whence-await.aspx) – jordanbtucker

+1

См. также [Асинхронное программирование с асинхронным и ожидаемым] (http://msdn.microsoft.com/en-us/library/hh191443.aspx) –

+0

Приятные примеры также можно найти по адресу http: // www .dotnetperls.com/асинхронный. –

ответ

61

Они просто talked about this at PDC вчера!

Await используется в сочетании с задачами (параллельное программирование) в .NET. Это ключевое слово, которое вводится в следующей версии .NET. Это более или менее позволяет вам «приостановить» выполнение метода, ожидающего завершения выполнения задачи. Вот краткий пример:

//create and run a new task 
Task<DataTable> dataTask = new Task<DataTable>(SomeCrazyDatabaseOperation); 

//run some other code immediately after this task is started and running 
ShowLoaderControl(); 
StartStoryboard(); 

//this will actually "pause" the code execution until the task completes. It doesn't lock the thread, but rather waits for the result, similar to an async callback 
// please so also note, that the task needs to be started before it can be awaited. Otherwise it will never return 
dataTask.Start(); 
DataTable table = await dataTask; 

//Now we can perform operations on the Task result, as if we're executing code after the async operation completed 
listBoxControl.DataContext = table; 
StopStoryboard(); 
HideLoaderControl(); 
+2

Когда это C# форма обещаний: http://en.wikipedia.org/wiki/Futures_and_promises – Gorgen

+12

Походит на Thread.Join(). –

+10

Напоминает мне о [COMEFROM] (http://en.wikipedia.org/wiki/COMEFROM) –

46

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

Подумайте об этом как о чем-то похожем на инструкцию yield return в методе, создающем IEnumerable. Когда время выполнения достигнет yield, оно в основном сохранит текущее состояние метода и вернет значение или ссылку. В следующий раз, когда IEnumerator.MoveNext() вызывается в возвращаемом объекте (который создается внутри среды выполнения), старое состояние метода восстанавливается в стек, и выполнение продолжается со следующей строки после yield return, как если бы мы никогда не уходили метод. Без этого ключевого слова тип IEnumerator должен быть настроен для хранения состояния и обработки запросов итерации с помощью методов, которые действительно могут стать ОЧЕНЬ сложными.

Аналогичным образом, метод, обозначенный как async, должен иметь не менее одного await. На этапе await среда выполнения сохранит состояние текущего потока и стек вызовов, сделает асинхронный вызов и вернется в цикл сообщений времени выполнения, чтобы обработать следующее сообщение и сохранить приложение в ответном режиме. Когда асинхронная операция завершена, при следующей возможности планирования стек вызовов для выполнения операции async возвращается и продолжается, как если бы вызов был синхронным.

Итак, эти два новых ключевых слова в основном упрощают кодирование асинхронных процессов, так же как yield return упрощают генерацию пользовательских счетчиков. Имея пару ключевых слов и небольшое знание фона, вы можете пропустить все запутанные и часто подверженные ошибкам детали традиционного асинхронного шаблона. Это будет НЕИСПРАВНО в почти любом приложении с графическим интерфейсом, основанном на событиях, например Winforms, WPF Silverlight.

30

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

Вот иллюстрация:

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     var task = DoWork(); 
     Console.WriteLine("Task status: " + task.Status); 
     Console.WriteLine("Waiting for ENTER"); 
     Console.ReadLine(); 
    } 

    private static async Task DoWork() 
    { 
     Console.WriteLine("Entered DoWork(). Sleeping 3"); 
     // imitating time consuming code 
     // in a real-world app this should be inside task, 
     // so method returns fast 
     Thread.Sleep(3000); 

     await Task.Run(() => 
      { 
       for (int i = 0; i < 10; i++) 
       { 
        Console.WriteLine("async task iteration " + i); 
        // imitating time consuming code 
        Thread.Sleep(1000); 
       } 
      }); 

     Console.WriteLine("Exiting DoWork()"); 
    } 
} 

Выход:

Поступил DoWork().Спящий 3
асинхронной задача итерации 0
Статус задачи: WaitingForActivation
Ожидание ENTER
асинхронной задачи итерации 1
асинхронной задачи итерации 2
асинхронной задачи итерации 3
асинхронной задачи итерации 4
асинхронной задачи итерации 5
асинхронная задача итерации 6
асинхронная задача итерация 7
асинхронная задача итерация 8
асинхронная задача итерации 9
Выход DoWork()

+0

Вы правы в том, что 'await' не останавливает ничего, но может иметь смысл думать, что это так. Принятый ответ имеет паузу в кавычках, подразумевая, что это неправда, это всего лишь способ думать о том, что происходит. Я бы сказал, что это не совсем так, но это, конечно, не совсем понятно. Что касается того, что не был в методе, отмеченном 'async', в то время, когда этот пост был написан, эта функция еще не была выпущена, а синтаксис для нее еще не был изобретен. Объяснение синтаксиса теперь, когда оно есть, прекрасно, просто понять, почему это не в этом ответе. – Servy

+0

Что касается этого ответа, почему вы используете 'Thread.Sleep' в своей асинхронной задаче? Вы действительно не должны использовать такой способ блокировки. Они должны быть заменены на 'waitait Task.Delay (X000); вместо этого, если вы не пытаетесь продемонстрировать что-то, включив их, в этом случае, пожалуйста, объясните, что вы пытаетесь показать, смешивая операции async и non-async в этом методе. – Servy

+0

@Servy 1. ok, имеет смысл – Anri

-2

Если бы я должен был реализовать в Java это будет выглядеть некоторые вещи, как это:

/** 
* @author Ilya Gazman 
*/ 
public abstract class SynchronizedTask{ 

    private ArrayList<Runnable> listeners = new ArrayList<Runnable>(); 

    private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(6, 6, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1000)); 

    public final void await(Runnable listener){ 
     synchronized (this) { 
      listeners.add(listener); 
     } 
    } 

    public void excecute(){ 
     onExcecute(); 
     for (int i = listeners.size() - 1; i >= 0; i--) { 
      Runnable runnable; 
      synchronized (this) { 
       runnable = listeners.remove(i); 
      } 
      threadPoolExecutor.execute(runnable); 
     } 
    } 

    protected abstract void onExcecute(); 
} 

Ваше приложение будет использовать его как это:

public class Test{ 
    private Job job = new Job(); 

    public Test() { 
     craeteSomeJobToRunInBackground(); 
     methode1(); 
     methode2(); 
    } 

    private void methode1(){ 
     System.out.println("Running methode 1"); 
     job.await(new Runnable() { 

      @Override 
      public void run() { 
       System.out.println("Continue to running methode 1"); 
      } 
     }); 
    } 

    private void methode2(){ 
     System.out.println("Running methode 2"); 
    } 

    private void craeteSomeJobToRunInBackground() { 
     new Thread(new Runnable() { 

      @Override 
      public void run() { 
       job.excecute(); 
      } 
     }).start(); 
    } 

    private class Job extends SynchronizedTask{ 

     @Override 
     protected void onExcecute() { 
      try { 
       Thread.sleep(1000); 
      } 
      catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      System.out.println("Job is done"); 
     } 
    } 
} 
10

Для тех, кто новичок в асинхронном программировании в .NET, вот (полностью фальшивая) аналогия в сценарии, с которым вы можете быть знакомы - вызовы AJAX с использованием JavaScript/jQuery. Простой пост JQuery AJAX выглядит следующим образом:

$.post(url, values, function(data) { 
    // AJAX call completed, do something with returned data here 
}); 

Причина мы обрабатываем результаты в функции обратного вызова, поэтому мы не блокировать текущий поток во время ожидания вызова AJAX, чтобы вернуться. Только когда ответ готов, будет активирован обратный вызов, освобождая текущий поток, чтобы делать другие вещи в среднем.

Теперь, если JavaScript поддерживает await ключевое слово (которое, конечно, это не (yet!)), можно добиться того же с этим:

var data = await $.post(url, values); 
// AJAX call completed, do something with returned data here 

Это намного чище, но он уверен, выглядит как мы ввели синхронный, блокирующий код. Но компилятор (фальшивый) JavaScript взял бы все после await и подключил его к обратному вызову, поэтому во время выполнения второй пример будет вести себя так же, как и первый.

Возможно, это не так, как будто вы сэкономите много работы, но когда дело доходит до вещей, таких как обработка исключений и контексты синхронизации, компилятор фактически делает лот тяжелой работы для вас. Более того, я бы рекомендовал FAQs, а затем Stephen Cleary's blog series.

+0

Придерживаясь этой поддельной аналогии (которая мне очень помогла, так спасибо!), Что значит «все после»? Все в пределах одной и той же функции (метода)? Или все после него, как и во всем, что могло быть добавлено в стек вызовов? –

+2

«Все после» = остальная часть метода. Компилятор эффективно перезаписывает остальную часть метода в качестве обратного вызова, и управление немедленно возвращается к вызывающей стороне текущего метода. –

+0

Блестящий Тодд, еще раз спасибо за ваше объяснение.Полезно и другим, я уверен. –

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