Боль параллелизма Тема, горутина, актер

Java Go модульный тест Akka

Эта статья основана на моем выступлении на встрече Gopher в Пекине 27 февраля с некоторыми дополнениями и корректировками. Представлен в публичный аккаунт «Архитектуры высокой доступности» впервые.

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

concurrent_vs_parallel

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

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

Почему параллельные программы такие сложные?


We believe that writing correct concurrent, fault-tolerant and scalableприложения слишком сложны в большинстве случаев потому, что мы используем неправильные инструменты и неправильный уровень абстракции. - Акка

Первое предложение официальной документации Akka хорошо сказано: причина, по которой так трудно писать правильные параллельные, отказоустойчивые и масштабируемые программы, заключается в том, что мы используем неправильные инструменты и неправильную абстракцию. (Конечно, документ изначально означал, что Akka был правильным инструментом, но мы можем посмотреть на это утверждение отдельно).

Затем разбираемся с абстракцией программы с самого начала. Начало нашей программы ориентировано на процесс, структура данных + функция. Позже, с объектно-ориентированным, объекты объединяют структуры данных и функции Мы хотим абстрагировать объекты, состояние и поведение таким образом, чтобы имитировать реальный мир. Но будь то процедурно-ориентированная функция или объектно-ориентированная функция, она по существу является организационной единицей блока кода и не содержит определения стратегии параллелизма блока кода. Так что для решения требования параллелизма было введено понятие Thread (потока).

Нить

  1. Режим ядра системы, более легкий процесс
  2. Запланировано ядром системы
  3. Несколько потоков одного и того же процесса могут совместно использовать ресурсы

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

Использование потоков относительно просто. Если вы считаете, что этот код должен быть параллельным, поместите его в отдельный поток для выполнения, а система отвечает за планирование. Когда использовать потоки и сколько потоков использовать, это вверх решать вызывающей стороне, но определение Сторона не знает, как вызывающая сторона будет использовать свой собственный код. Многие проблемы параллелизма вызваны неправильным использованием. Например, карта в Go и HashMap в Java не являются одновременно безопасными и используются не по назначению. в многопоточной среде вызовет проблемы. Это также приносит сложность:

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

Для решения вышеуказанных задач мы внедряем множество сложных механизмов, обеспечивающих:

  • Mutex(Lock) (пакет синхронизации в Go, параллельный пакет в Java) защищает данные с помощью мьютекса, но с блокировкой параллелизм явно снижается.
  • Семафор управляет параллелизмом через семафоры или как межпоточные сигнальные (сигнальные) уведомления.
  • volatile Java специально представила ключевое слово volatile, чтобы уменьшить использование блокировок в ситуациях только для чтения.
  • Функция сравнения и замены гарантирует атомарность благодаря механизму CAS, предоставляемому аппаратным обеспечением, который также является механизмом снижения стоимости блокировок.

Если две вышеуказанные проблемы просто увеличивают сложность, мы можем решить ее в определенной степени путем углубленного изучения, тщательного CodeReview и всестороннего параллельного тестирования (например, добавления параметра -race к модульному тестированию в языке Go) (конечно, это тоже спорно, в некоторых документах считается, что у большинства текущих параллельных программ нет проблем, но степень параллелизма недостаточна.Если количество ядер ЦП продолжает увеличиваться, а программа работает в течение более длительного времени, трудно гарантия, что проблем не будет). Но больше всего раздражает следующий вопрос:

Сколько потоков необходимо в системе?

Начнем с проблемой аппаратных ресурсов для начала, рассмотрите стоимость следующего потока:

  • Память (пространство стека потоков)
    Каждому потоку необходимо пространство стека (Stack) для сохранения состояния приостановки (suspending). Пространство стека Java (64-разрядная виртуальная машина) по умолчанию составляет 1024 КБ, не считая другой памяти, только пространство стека, для запуска 1024 потоков требуется 1 ГБ памяти. Хотя этим можно управлять с помощью параметра -Xss, поскольку потоки по сути являются процессами, система предполагает, что они будут выполняться в течение длительного времени.Слишком маленький размер стека приведет к несколько более сложным рекурсивным вызовам (таким как сложное сопоставление регулярных выражений), что приводит к переполнению стека. Таким образом, корректировка параметров может решить симптомы, но не коренные причины.
  • Стоимость планирования (переключение контекста)
    Нестрогий тест, который я провел на персональном компьютере, моделирует, что два потока пробуждают друг друга и приостанавливаются по очереди.Стоимость переключения потоков составляет около 6000 нс/время. При этом не учитывается влияние размера стека. В иностранной статье специально анализируется стоимость переключения потоков, и в основном делается вывод о том, что стоимость переключения напрямую связана с размером используемого пространства стека.

    context switch

  • использование процессора
    Одной из наших основных целей для параллелизма является то, что у нас есть несколько ядер.Мы хотим улучшить использование ЦП и максимально использовать аппаратные ресурсы.С этой точки зрения, сколько потоков мы должны использовать?
    cpu ratio

    Мы можем рассчитать это по формуле 100/(15+5)*4=20, и 20 потоков являются наиболее подходящими. Но с одной стороны время в сети не фиксировано, с другой стороны, а если учитывать другие узкие места? Например, блокировки, такие как пулы соединений с базой данных, более сложны.

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

  • Ничего страшного, если ребенок не ест (но ребенок игривый, может быть, он хочет играть, если не ест)
  • Ребенку полезно есть (ерунда, откуда ты знаешь, что ребенок сыт? Ребенок не может говорить)
  • Увеличивайте постепенно, наблюдайте за временем, а затем вычисляйте среднее значение (может быть, это обычная стратегия, которую мы используем для настройки потоков, но сколько приращений уместно?)
  • Если ребенку SPIT, не кормите (если вы используете постепенный инкрементный режим, вы можете достичь этого граничного состояния. Производительность системы, если нить обращается, не увеличивайте нить)
  • Я плохо контролировал границу, и ребенок был сломан (этот отец-медведь слишком страшный. Но при настройке нити система может случайно зависнуть)

Из этого примера мы видим, что очень трудно наблюдать из внешней системы или вычислять эмпирическим путем. Итак, вывод такой:

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

Однако компьютер не говорит сам по себе, как он может управлять собой?

Но мы можем сделать вывод из приведенного выше обсуждения:

  • Высокая стоимость потоков (память, планирование) Невозможно создать в масштабе
  • Это должно решаться динамически языком или фреймворком.

схема пула потоков


После Java 1.5 серия Executor Дуга Ли включена в JDK по умолчанию, что является типичной схемой пула потоков.

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

новые идеи


Из предыдущего анализа мы видим, что если поток работает всегда, нам нужно только установить количество потоков равным количеству ядер ЦП, чтобы можно было максимизировать ЦП и снизить стоимость переключения и использование памяти. . Но как это сделать?

Чен Ли внесен в список, и те, кто не может остановиться

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

Обычно иметь два варианта:

  1. Схема асинхронного обратного вызоваТипично такие как NodeJS, в случае блокировки, например, сетевых вызовов, прописать метод обратного вызова (на самом деле, он также включает некоторые объекты данных контекста) в планировщик ввода-вывода (libev под linux, планировщик находится в другом потоке), текущий thread был освобожден для других целей. Когда данные будут готовы, планировщик передаст результат методу обратного вызова и выполнит его.Выполнение фактически происходит не в том потоке, который первоначально инициировал запрос, но об этом не знает пользователь. Но проблема с этим методом в том, что легко столкнуться с адом обратных вызовов, потому что все блокирующие операции должны быть асинхронными, иначе система зависнет. Кроме того, асинхронный метод немного противоречит привычке человеческого мышления, и люди все еще привыкли к синхронному методу.

  2. Решение GreenThread/Coroutine/FiberЭта схема на самом деле мало чем отличается от вышеописанной схемы по сути, ключ кроется в механизме сохранения и исполнения callback-контекста. Чтобы решить проблему, вызванную методом обратного вызова, идея этого решения состоит в том, чтобы писать код последовательно, но когда встречаются блокирующие вызовы, такие как IO, текущий фрагмент кода приостанавливается, контекст сохраняется, а текущая нить сдается. Подождите, пока событие ввода-вывода вернется, а затем найдите поток, чтобы позволить текущему фрагменту кода возобновить контекст и продолжить выполнение.При написании кода он как бы синхронизируется, как если бы он был завершен в том же потоке, но на самом деле система может переключать потоки, но это никак не влияет на программу.

GreenThread

  • Пользовательское пространство Во-первых, оно находится в пользовательском пространстве, чтобы избежать затрат, связанных с переключением между режимом ядра и пользовательским режимом.
  • Планирование языком или слоем кадра
  • Меньшее пространство стека позволяет создавать большое количество экземпляров (миллионы уровней)

несколько концепций

  • Понятие Continuation может быть незнакомо тем, кто не знаком с программированием FP, но может быть просто, как следует из названия, его можно понимать как механизм, который позволяет нашей программе сделать паузу, а затем продолжить следующий вызов (contine ) начинается с того места, где была сделана последняя пауза. . Это эквивалентно еще одной записи для вызова программы.
  • Coroutine — это реализация Continuation, которая обычно выражается как компонент или библиотека классов на уровне языка. В основном он обеспечивает механизмы выхода и возобновления.
  • Файбер и Корутин на самом деле две стороны одного тела.Они в основном описываются на системном уровне.Понятно,что после запуска Корутина будет Файбер.

Goroutine


Goroutine на самом деле является развитием и реализацией предыдущих решений серии GreenThread.

  • Во-первых, он имеет встроенный механизм Coroutine. Из-за планирования в пользовательском режиме должен быть механизм, позволяющий приостанавливать/продолжать выполнение фрагментов кода.
  • Во-вторых, он имеет встроенный планировщик, который реализует многопоточное параллельное планирование Coroutine, и в то же время за счет инкапсуляции сетевых и других библиотек детали планирования скрыты от пользователей.
  • Наконец, механизм канала предоставляется для связи между горутинами для реализации модели параллелизма CSP (обмен последовательными процессами). Поскольку канал Go предоставляется с помощью ключевых слов синтаксиса, многие детали скрыты от пользователя. По сути, Channel в Go — это тот же механизм, что и SynchronousQueue в Java: если есть буфер, то это на самом деле ArrayBlockQueue.

горутин планировщик

go-scheduler

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

  1. M обозначает системный поток, P обозначает процессор (ядро), а G обозначает Goroutine. Go реализует планирование M:N, что означает, что между потоками и горутинами существует связь «многие ко многим». Это не реализовано во многих планировщиках GreenThread/Coroutine. Например, поток до Java 1.1 на самом деле GreenThread (слово происходит от Java), но потому, что не реализовано планирование «многие ко многим», то есть параллелизм толком не реализован, и преимущества многоядерности не могут быть воспроизведены , поэтому позже он был изменен, чтобы основываться на ядре системы.
  2. Если система системной резьбы заблокирована, расположена на потоке Goroutine будет мигрироваться. Конечно, существуют и другие механизмы, такие как M FLY, если не глобальные задачи очередей могут выполнять задачи от других M Reake, эквивалентным механизмом ребакана. Здесь не уточняется, необходимо увидеть специальный анализ статьи.
  3. Конкретная стратегия реализации аналогична механизму, который мы анализировали ранее. Когда система запускается, она запускает независимый фоновый поток (не в пуле потоков планирования Goroutine) и запускает опрос netpoll. Когда горутина инициирует сетевой запрос, сетевая библиотека связывает fd (файловый дескриптор) с pollDesc (структура, используемая для описания netpoll, включая горутину, заблокированную из-за чтения/записи этого fd), а затем вызывает runtime.gopark. method приостанавливает текущую Goroutine. Когда фоновый опрос netpoll получает событие epoll (в среде Linux), он извлечет из события pollDesc, найдет связанную блокирующую горутину и восстановит ее.

Горутины — серебряная пуля?

Горутина значительно снижает стоимость разработки параллелизма.Можем ли мы просто работать там, где нам нужен параллелизм?

Go решает проблему использования ЦП с помощью планирования Goroutine. Но как быть с другими узкими местами ресурсов? Например, общие ресурсы с блокировками, такие как соединения с базой данных. В сценарии онлайн-приложения в Интернете, если каждый запрос передается в горутину, когда возникает узкое место в ресурсах, большое количество горутин будет заблокировано, и, наконец, время ожидания запроса пользователя истекает. В это время необходимо использовать пул горутин для управления потоком, и снова возникает вопрос: сколько горутин уместно в пуле?

Так что эта проблема принципиально не решена.

Модель актера


Актеры могут быть непростыми для понимания тем, кто не знаком с этой концепцией.Концепция Актеров на самом деле похожа на объекты в объектно-ориентированном подходе, который является абстракцией. Абстракция объектно-ориентированного программирования к реальности такова: объект = атрибут + поведение (метод), но когда пользователь вызывает поведение объекта (метод), он фактически занимает квант времени процессора вызывающей стороны, а является ли он параллельным, также определяется звонящий. . Эта абстракция на самом деле отличается от реального мира. Реальный мир больше похож на абстракцию Актеров, которые общаются друг с другом посредством асинхронных сообщений. Например, если вы поздороваетесь с красавицей, ответит ли она или нет, зависит от самой красавицы, это происходит в собственном мозгу красавицы и не будет занимать мозг отправителя.

Итак, Актер обладает следующими характеристиками:

  • Обработка. Актеры могут выполнять вычисления, не занимая квант времени процессора вызывающей стороны, а стратегия параллелизма также определяется сама по себе.
  • Хранилище — акторы могут сохранять состояние
  • Общение — актеры могут общаться, отправляя сообщения

Актеры следуют этим правилам:

  • Отправить сообщения другим актерам
  • Создать другие актеры
  • Принимать и обрабатывать сообщения, изменять их состояние

Цель актера:

  • Актеры могут обновляться независимо друг от друга, что позволяет выполнять «горячее» обновление. Поскольку акторы не связаны друг с другом напрямую, они являются относительно независимыми объектами и могут обновляться в горячем режиме.
  • Беспрепятственное соединение локальных и удаленных вызовов Поскольку Актеры используют механизм связи на основе сообщений, независимо от того, взаимодействуют ли они с локальными или удаленными Актерами посредством сообщений, устраняется разница между локальным и удаленным.
  • Связь между отказоустойчивыми субъектами является асинхронной, отправитель просто отправляет и не заботится о тайм-аутах и ​​ошибках, которые берут на себя уровень инфраструктуры и независимые механизмы обработки ошибок.
  • Легкое расширение, естественное распределение, потому что механизм связи актера мостит локальные и удаленные вызовы, когда локальный актер не может обрабатывать его, вы можете запустить актер на удаленном узле и переслать сообщение.

Реализация актера:

  • Эталонный тест модели Erlang/OTP Actor и другие реализации в основном относятся к модели Erlang в определенной степени. Реализовано горячее обновление и распространено.
  • Akka (Scala, Java) реализована на основе потоков и шаблонов асинхронного обратного вызова. Поскольку в Java нет Fiber, он основан на потоках. Чтобы избежать блокировки потока, все блокирующие операции в Akka должны быть асинхронными. Либо асинхронный фреймворк, предоставляемый Akka, либо механизм Future-callback преобразуется в режим обратного вызова. Распределение достигнуто, но горячее обновление еще не поддерживается.
  • Quasar (Java) Чтобы решить проблему блокирующего обратного вызова Akka, Quasar реализует Coroutine/Fiber в Java посредством улучшения байт-кода. При этом горячее обновление осуществляется через механизм ClassLoader. Недостатком является то, что расширение байт-кода выполняется через механизм javaagent при запуске системы.

Golang CSP VS Actor


Девиз обоих:

Не общайтесь, делясь памятью, делитесь памятью, общаясь

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

  • В модели CSP сообщения и каналы являются субъектами, а обработчики являются анонимными.
    То есть отправителю нужно заботиться о типе своего собственного сообщения и о том, в какой канал он должен писать, но ему не нужно заботиться о том, кто его потребляет и сколько существует потребителей. Каналы обычно привязаны к типу, и канал записывает сообщения только одного типа, поэтому CSP должен поддерживать механизм alt/select и одновременно отслеживать несколько каналов. Канал является синхронным режимом (канал Golang поддерживает буферы и поддерживает определенную степень асинхронности). Логика этого заключается в том, что отправитель очень обеспокоен тем, обработано ли сообщение. CSP должен гарантировать, что каждое сообщение обрабатывается нормально, и он будет блокировать, если он не обрабатывается.
  • В модели Актера Актер является основным телом, а Почтовый ящик (аналогичный Каналу CSP) прозрачен.
    Другими словами, предполагается, что отправителю важно, кто получает сообщение, а не тип сообщения и канал. Таким образом, Mailbox находится в асинхронном режиме, отправитель не может предполагать, что отправленное сообщение должно быть получено и обработано. Модель актора должна поддерживать надежный механизм сопоставления с образцом, потому что независимо от того, какой тип сообщения будет отправлен через один и тот же канал, его необходимо распространять через механизм сопоставления с образцом. Логика этого заключается в том, что реальный мир по своей природе асинхронен и недетерминирован, поэтому программа также должна адаптироваться к программированию перед лицом неопределенности. С появлением параллелизма первоначальный детерминистический подход к программированию подвергся сомнению, и Актер воплощает это непосредственно в шаблоне.

С этой точки зрения режим CSP больше подходит для механизма распределения задач режима Boss-Worker, он не такой навязчивый, и конкретную задачу можно решить с помощью CSP в существующей системе. Он не пытается решить проблему отказоустойчивости связи по тайм-ауту, с которой все еще должен справиться инициатор. В то же время, поскольку Канал является явным, хотя и возможно реализовать удаленный Канал через нетчан (исходный механизм нетчана, предоставляемый Go, был заброшен из-за его сложности, новый нетчан обсуждается), но это сложно сделать прозрачным. пользователю. Актер — это совершенно новая абстракция, и использование Актера сталкивается с изменениями во всем механизме архитектуры приложения и образе мышления. Проблемы, которые он пытается решить, шире, например, отказоустойчивость, например распределенная. Но проблема с Актером в том, что при текущей эффективности планирования даже с таким механизмом, как Goroutine, трудно добиться эффективности прямых вызовов методов. В настоящее время необходимо реализовать язык «все является субъектом», подобно тому, как в ОО «все является объектом», и должна возникнуть проблема с эффективностью. Поэтому компромисс заключается в абстрагировании компонентов определенного уровня системы в Актеры на основе ОО.

Еще немного ржавчины


Rust решает проблему проблемы параллелизма - признать, что ресурсы реального мира всегда ограничены. Трудно избежать совместного использования ресурсов, не пытаться полностью избежать обмена ресурсами, он считает, что проблема не в разделе ресурсов, но неправильно. Обмен ресурсами. Например, когда мы упоминали ранее, большинство типов определений языка не ограничивают, как может использовать абонент, может пройти документ или отметку (например, @threadsafe, @ netthreadsafe аннотацию в Java), но также можно использовать только для использования только для использования только для использования только Подсказка, не может помешать абонеру неправильно использовать. Хотя Go предоставляет механизм -race, его можно обнаружить с помощью этого параметра, запустив тестирование подразделения, но если ваш модульный тест недостаточно, охват не обнаруживает его. Итак, раствор ржавчины:

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

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

в заключении

Революция еще не удалась, товарищам еще надо потрудиться

В этой статье мы рассматриваем проблемы параллелизма и решения вместе. Хотя каждый из них имеет различные преимущества и сценарии использования, но проблема, вызванная одновременным использованием, все еще далека от решения. Так что нужно стремиться, у нас также есть возможность ах.

Наконец кинуть кирпич Идея: Реализация Актера на Горутине?

  • Распределенная проблема эффективности одной машины решена. Можете ли вы попытаться решить проблему распределенной эффективности?
  • Интеграция с контейнерными кластерами Текущие решения автоматического масштабирования в основном реализуются путем мониторинга сервера или LoadBalancer и установки порогового значения. Как и в примере с кормлением, о котором я упоминал ранее, это решение основано на опыте, но если система сочетается с внешними кластерами, это можно сделать более детально и разумно.
  • Самоуправление Конечной целью первых двух пунктов является создание системы, которая может управлять собой. Учащиеся, которые занимались эксплуатацией и обслуживанием системы, знают, что мы заботимся о системе так же, как заботимся о детях.Нам необходимо постоянно контролировать различные состояния системы, принимать различные аварийные сигналы от системы, а затем устранять неполадки и выполнять первая помощь. Когда ребенок вырастет, может ли система тоже расти и управлять собой? Хотя эта цель кажется еще далекой, я думаю, что ее можно ожидать.

qrcode_jolestar_blog2

Цитаты и дополнительная литература


  1. Видео этого выступления
  2. Выступление в этой газетеpdf
  3. CSP model paper
  4. Actor model paper
  5. Quantifying The Cost of Context Switch
  6. JCSP Библиотека для реализации моделей CSP в Java.
  7. Overview of Modern Concurrency and Parallelism Concepts
  8. Голанг нетчан обсуждение
  9. quasar vs akka
  10. параллелизм в официальном блоге golang — это не параллелизм
  11. планировщик go, исходник планировщика картинка в тексте
  12. обработка 1 миллиона запросов в минуту с помощью golang Практика управления потоком с горутиной

ВОПРОСЫ-ОТВЕТЫ:


Высокодоступная архитектура общедоступной учетной записи пользователя сети "Chuang": У меня есть вопрос к вам. Вы сказали, что 1024 потока требуют 1G пространства в качестве пространства стека. Когда поступает адресное пространство потоков и процессов, адресное пространство потоков и процессов виртуальное пространство. Когда вы на самом деле не используете этот виртуальный адрес, он не сопоставляет страницы физической памяти с виртуальной памятью. То есть, если каждый поток не такой глубокий, он не будет записывать все пространство стека в память. , 1024 потока на самом деле не будут потреблять столько памяти.

Ответ: Вы правы, куча Java и память стека — это виртуальная память, на самом деле запуск потока не займет столько памяти сразу. Но поток работает долго.После роста стека пространство не будет высвобождаться, то есть будет постепенно увеличиваться до предела xss. Это просто для иллюстрации стоимости потоков. Кроме того, даже если это пустой поток (сон после запуска), согласно моему тесту, сервер с 1 ядром и 1G будет зависать после запуска более 30 000 потоков (сначала нужно изменить максимальное количество системных потоков, в /proc/sys/kernel/threads-max) все еще существует большой разрыв с идеальным уровнем в миллион.