Синхронный и асинхронный
Веб-синхронный вызов
Браузер/клиент инициирует запрос, веб-сервер запускает поток для обработки запроса, и когда запрос обрабатывается, веб-сервер возвращает результат обработки, который представляет собой синхронный вызов.
Эта статья и ссылка на изображение (то же самое ниже) - Mu Zixu: асинхронный вызов [WebAsyncTask]
В обычных сценариях, если нагрузка на сервер невелика, а серверная служба мощная, проблем с синхронными вызовами не возникает.
Однако в сценариях с высокой степенью параллелизма общее количество потоков, запрашивающих сервер, ограничено.Если поток всегда блокируется, это повлияет на пропускную способность системы.
Веб-асинхронный вызов
Так называемый асинхронный запрос должен вернуться сразу после вызова текущего потока и продолжить обработку других задач.После того, как текущий вызов успешно обработан, для обработки возвращаемого результата используется поток обратного вызова.
Давайте возьмем в качестве аналогии пример работы по дому: в прошлом, когда вы использовали огонь для приготовления пищи, вы могли только стоять рядом, чтобы добавить дрова и огонь, а затем ставить посуду, когда рис был готов; после того, как рисоварка закончила добавили необходимые материалы для приготовления и выдали инструкцию по приготовлению, рисоварка начнет работать сама по себе, и вы сможете выйти поставить посуду.Когда рис будет готов, рисоварка автоматически подаст звуковой сигнал.Уведомит вас, чтобы прийти забрать съев еду, ее эффективность значительно повысится, а ваши возможности параллельной обработки резко возрастут.
После Spring MVC 3.2 была введена асинхронная обработка запросов на основе Servlet 3, которая может реализовывать следующие асинхронные вызовы.
Сравнение синхронных и асинхронных вызовов веб-запросов
Давайте быстро продемонстрируем использование WebAsyncTask и разницу между синхронными и асинхронными вызовами на простом примере синхронного и асинхронного сравнения.
две задачи
Сначала определите контроллер и добавьте два метода для представления двух задач, которые должны выполняться веб-запросом, и эти две задачи будут выполняться в течение 3 секунд соответственно.
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.WebAsyncTask;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* WebAsyncTask
*
* @author ijiangtao
* @create 2019-07-03 11:31
**/
@RestController
public class WebAsyncTaskController {
private Map<String, String> buildResult() {
System.out.println("building result");
Map<String, String> result = new HashMap<>();
try {
Thread.sleep(3 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < 1 * 1000; i++) {
result.put(i + "-key", i + "value");
}
return result;
}
private void doTask() {
System.out.println("do some tasks");
try {
Thread.sleep(3 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Выполнять веб-запросы синхронно
@GetMapping("/r1")
public Map<String, String> r1() {
Instant now = Instant.now();
Map<String, String> result = buildResult();
doTask();
System.out.println("r1 time consumption: " + ChronoUnit.SECONDS.between(now, Instant.now()) + " seconds");
return result;
}
В случае синхронного выполнения запросов все задачи в обработке веб-запросов выполняются параллельно, а конечное время выполнения является суммой всех задач.
Выполнять веб-запросы асинхронно
@GetMapping("/r2")
public WebAsyncTask<Map<String, String>> r2() {
Instant now = Instant.now();
Callable<Map<String, String>> callable = new Callable<Map<String, String>>() {
@Override
public Map<String, String> call() throws Exception {
return buildResult();
}
};
doTask();
WebAsyncTask<Map<String, String>> webAsyncTask = new WebAsyncTask<>(callable);
System.out.println("r2 time consumption: " + ChronoUnit.SECONDS.between(now, Instant.now()) + " seconds");
return webAsyncTask;
}
Для асинхронно выполняемых веб-запросов мы определяем задачу возврата результата веб-запроса, реализуя метод call интерфейса Callable, и выполняем задачу через WebAsyncTask.Когда задача вызывается и возвращается немедленно, другие задачи могут выполняться в параллельно, и, наконец, когда выполнение WebAsyncTask завершается. Позднее веб-запрос возвращается.
Настроить асинхронное выполнение веб-запросов
Если вы просто хотите добиться асинхронной и параллельной обработки, вы также можете использовать механизм Future, предоставляемый JDK.Прелесть WebAsyncTask заключается в том, что он предоставляет конфигурацию тайм-аута, асинхронный исполнитель задач и обратный вызов завершения выполнения, исключение выполнения и обратный вызов после тайм-аута.
package net.ijiangtao.tech.demo.webasynctask.controller;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.WebAsyncTask;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* WebAsyncTask
*
* @author ijiangtao
* @create 2019-07-03 11:31
**/
@RestController
public class WebAsyncTask2Controller {
@GetMapping("/r3")
public WebAsyncTask<Map<String, String>> r2() {
Instant now = Instant.now();
Callable<Map<String, String>> callable = new Callable<Map<String, String>>() {
@Override
public Map<String, String> call() throws Exception {
return buildResult();
}
};
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
executor.setThreadNamePrefix("WebAsyncTask2-");
WebAsyncTask<Map<String, String>> webAsyncTask = new WebAsyncTask<>(2 * 1000L, executor, callable);
webAsyncTask.onCompletion(new Runnable() {
@Override
public void run() {
System.out.println("Completion");
}
});
webAsyncTask.onError(new Callable<Map<String, String>>() {
@Override
public Map<String, String> call() throws Exception {
System.out.println("Error");
return new HashMap<>();
}
});
webAsyncTask.onTimeout(new Callable<Map<String, String>>() {
@Override
public Map<String, String> call() throws Exception {
System.out.println("Timeout");
Map<String, String> timeOutResutl = new HashMap<>();
timeOutResutl.put("timeout", "result");
return timeOutResutl;
}
});
doTask();
System.out.println("r2 time consumption: " + ChronoUnit.SECONDS.between(now, Instant.now()) + " seconds");
return webAsyncTask;
}
private Map<String, String> buildResult() {
System.out.println("building result");
Map<String, String> result = new HashMap<>();
try {
Thread.sleep(3 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < 1 * 1000; i++) {
result.put(i + "-key", i + "value");
}
return result;
}
private void doTask() {
System.out.println("do some tasks");
try {
Thread.sleep(3 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Пример в коде демонстрирует тайм-аутonTimeout
более поздний механизм обработки.
Суммировать
В этой статье объясняетсяWebAsyncTask
Механизм реализации,WebAsyncTask
Реализован асинхронный вызов веб-запросов. Основная цель — освободить контейнерные потоки и повысить пропускную способность сервера. Это очень практично в сценариях с большим трафиком и высокой степенью параллелизма (таких как паническая покупка и т. д.).
Ссылки по теме
связанные ресурсы
Пример исходного кода Github этой статьи
Справочная статья
Асинхронный вызов [WebAsyncTask]