Различия между C # async и Java ExecutorService - PullRequest
12 голосов
/ 28 марта 2012

C # имеет замечательную новую функцию

public Task<string> async f()
{
    string r = LongCompute();
    return r;
}

, но это не эквивалентно

public Future<String> f() {
    return Globals.executorService.submit(new Callable<String>() {
        public String call() throws Exception {
            String r = longCompute();
            return r;
        }
    });
}

, где в Java вы более гибко выбираете пул потоков, в котором будет выполняться задачазапустить.

А как насчет ждать?Это эквивалентно простому вызову get

string s = await f();

, как

String s = f().get();

Есть ли что-то еще в C #, или это действительно синтаксический сахар для версии Java?(Я не гуру C #, поэтому я могу что-то упустить).

Ответы [ 3 ]

29 голосов
/ 28 марта 2012

Нет, await - это , а не , как просто вызов get(). Это значительно больше.

Когда вы используете выражение await в C #, компилятор эффективно создает продолжение, так что, если ожидаемое еще не завершено, метод может немедленно вернуться и продолжить обработку только после его завершения. Продолжение будет выполняться в соответствующем контексте - поэтому, если вы находитесь в потоке пользовательского интерфейса до выражения await, вы продолжите работу в потоке пользовательского интерфейса позже, но без блокировки потока пользовательского интерфейса, пока вы ожидаете результата. Например:

public async void HandleButtonClick(object sender, EventArgs e)
{
    // All of this method will run in the UI thread, which it needs
    // to as it touches the UI... however, it won't block when it does
    // the web operation.

    string url = urlTextBox.Text;
    WebClient client = new WebClient();
    string webText = await client.DownloadStringTaskAsync(url);

    // Continuation... automatically called in the UI thread, with appropriate
    // context (local variables etc) which we used earlier.
    sizeTextBox.Text = string.Format("{0}: {1}", url, webText.Length); 
}

В конечном итоге это все синтаксический сахар, но намного более сложный сахар, чем вы показали.

В Интернете уже есть много подробной информации. Например:

10 голосов
/ 04 июля 2014

Джон не объяснил реальную точку .

Java * ExecutorService основан на потоков , в то время как await в C # можно сказать, что он основанна волокон .

Оба допускают многозадачность, которая разделяет вычислительные ресурсы между параллельными функциями (т. е. функциями, которые выполняются «одновременно»).Первый тип многозадачности называется упреждающим , а второй кооперативным .Исторически упреждающая многозадачность считалась более продвинутой и превосходящей кооперативную.Действительно, до того, как приоритетные многозадачности стали поддерживаться потребительскими операционными системами, компьютеры действительно были засосаны.Однако упреждающая многозадачность имеет свои недостатки.Это может быть сложно для программирования, и он использует больше памяти.

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

В любом случае, дело в том, что ExecutorService и await не являются непосредственно сопоставимыми, и await, в общем, не превосходит настоящую многопоточность (за исключением того, что он имеет хороший синтаксический сахар).Причина, по которой C # включает await (и основывается на кооперативной многозадачности), заключается в том, что основные наборы инструментов GUI на платформе не предназначены для многопоточности, и их рефакторинг для поддержки параллелизма потребует огромного количества работы.Совместная многозадачность хорошо работает для пользовательского интерфейса, потому что большинство обработчиков событий короткие и могут выполняться последовательно.await расширяет концепцию цикла событий, позволяя длинным обработчикам событий приостанавливать себя и возобновлять работу после того, как функция рендеринга получит шанс на запуск.Все это происходит в одном потоке на одном ядре ЦП.

То, что они оба находят общий язык, заключается в том, что они являются обеими формами многозадачности, а Future.get и await Task являются обеими формами синхронизации.

Как и следовало ожидать, C # не без хорошей поддержки потоков и пулов потоков.Точно так же Java содержит волокна / сопрограммы / асинхронность во многих библиотеках, таких как Servlet 3.0 и javafx.concurrent.Task.

В ответ на Jon Skeet: Continuation (как механизм реализации пользовательского интерфейсаволокна называется) нетривиально, но потоки не менее сложны в своей реализации.Джон, возможно, был отброшен, потому что алгоритмы потоков находятся в ОС, а не в компиляторе или во время выполнения .NET.

4 голосов
/ 07 июля 2013

Просто чтобы расширить правильный ответ Джона Скита.

Не является Java-аналогом выражений C # await. Однако некоторые фреймворки Java имеют одинаковую функциональность:

Фактически, они генерируют процедуры или код конечного автомата на лету.

...