Что делает новая функция ожидания C#? [закрытый]


может ли кто-нибудь объяснить, что такое

5 82

5 ответов:

они просто говорили об этом в PDC вчера!

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

//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();

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

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

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

Итак, эти два новых ключевых слова в основном упрощают кодирование асинхронных процессов, так же как yield return упрощена генерация пользовательских перечислений. С парой ключевых слов и небольшим фоновым знанием вы можете пропустить все запутанные и часто подверженные ошибкам детали традиционного асинхронного шаблона. Это будет бесценно в значительной степени любой событийных GUI-приложения как приложения WinForms, в WPF и Silverlight.

в настоящее время принимаются ответ вводит в заблуждение. 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 ()

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

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

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

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

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

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

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

Если бы мне пришлось реализовать его на 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");
        }
    }
}