Насколько велик пул параллельных потоков Java?

Java

предисловие

В нашем повседневном процессе развития бизнеса мы будем более или менее использовать параллельные функции. Тогда в процессе использования функции параллелизма вы обязательно столкнетесь со следующей проблемой
Насколько велик пул параллельных потоков?
Обычно программисты, которые немного стары, возможно, слышали это утверждение (где N — количество процессоров)
  1. Приложения с интенсивным использованием ЦП с размером пула потоков, равным N + 1
  2. Приложения с интенсивным вводом-выводом, размер пула потоков равен 2N.
Это утверждение верно?
На самом деле это крайне неправильно. Так почему?
Прежде всего, давайте посмотрим на это с противоположной стороны, если предположить, что это утверждение верно, то не имеет значения, сколько сервисов мы развертываем на сервере. Поскольку размер пула потоков может быть связан только с количеством ядер на сервере, это утверждение неверно. Итак, как вы должны установить размер?
Предполагая, что это приложение является гибридом двух, в котором задачи интенсивно используют как ЦП, так и ввод-вывод, как мы можем изменить настройки? Разве не только винчестер кинуть решать?
Так как же нам установить размер пула потоков? Существуют ли какие-либо конкретные практические методы, которые помогут вам приземлиться? Давайте посмотрим глубже.
Закон Литтла
Количество запросов к системе равно произведению скорости поступления запросов и среднего времени, затрачиваемого на каждый отдельный запрос.
Предполагая, что сервер имеет одно ядро, соответствующему бизнесу необходимо гарантировать объем запросов (QPS): 10, а обработка запроса занимает 1 секунду, тогда сервер обрабатывает 10 запросов в каждый момент времени, то есть 10 нужны нитки.
Точно так же мы можем использовать закон Литтла для определения размера пула потоков. Нам просто нужно рассчитать скорость поступления запросов и среднее время обработки запросов. Затем, применяя приведенные выше значения к закону Литтла, можно рассчитать среднее количество запросов в системе. Формула оценки выглядит следующим образом
*Размер пула потоков = ((время ввода-вывода потока + время ЦП потока)/время ЦП потока) Количество ЦП**

конкретная практика

Из формулы мы знаем, что нам нужны 3 конкретных значения
  1. Время, потребляемое запросом (время ввода-вывода потока + время ЦП потока)
  2. Время вычисления запроса (процессорное время потока)
  3. Количество процессоров

Потребление времени запроса

В контейнере веб-сервиса время, затраченное до и после получения запроса, может быть перехвачено фильтром.
public class MoniterFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(MoniterFilter.class);
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
            ServletException {
long start = System.currentTimeMillis();
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String uri = httpRequest.getRequestURI();
        String params = getQueryString(httpRequest);
try {
            chain.doFilter(httpRequest, httpResponse);
        } finally {
long cost = System.currentTimeMillis() - start;
            logger.info("access url [{}{}], cost time [{}] ms )", uri, params, cost);
        }
private String getQueryString(HttpServletRequest req) {
        StringBuilder buffer = new StringBuilder("?");
        Enumeration<String> emParams = req.getParameterNames();
try {
while (emParams.hasMoreElements()) {
                String sParam = emParams.nextElement();
                String sValues = req.getParameter(sParam);
                buffer.append(sParam).append("=").append(sValues).append("&");
            }
return buffer.substring(0, buffer.length() - 1);
        } catch (Exception e) {
            logger.error("get post arguments error", buffer.toString());
        }
return "";
    }
}

Время вычислений процессора

Время расчета ЦП = общее время запроса - время ввода-вывода ЦП
Предполагая, что в запросе есть операция запроса к БД, если вы знаете, сколько времени (время ввода-вывода процессора) на запрос к БД, время расчета не выйдет. Давайте посмотрим, как записать время, затрачиваемое на запрос к БД. Запрос БД лаконично и ясно.
Добавьте аспект AOP (динамический прокси-сервер JDK / CGLIB), чтобы получить поток ввода-вывода, отнимающий много времени. Код выглядит следующим образом, пожалуйста, обратитесь к:
public class DaoInterceptor implements MethodInterceptor {
private static final Logger logger = LoggerFactory.getLogger(DaoInterceptor.class);
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
        StopWatch watch = new StopWatch();
        watch.start();
        Object result = null;
        Throwable t = null;
try {
            result = invocation.proceed();
        } catch (Throwable e) {
            t = e == null ? null : e.getCause();
throw e;
        } finally {
            watch.stop();
            logger.info("({}ms)", watch.getTotalTimeMillis());
        }
return result;
    }
}

Количество процессоров

Количество логических ЦП, количество ЦП, на которое следует ссылаться при установке размера пула потоков
cat /proc/cpuinfo| grep "processor"| wc -l

Суммировать

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

Наконец

Прошу всех обратить внимание на мой официальный аккаунт [Программист в погоне за ветром], в нем будут обновляться статьи, а также размещаться отсортированная информация.