
Node.js теперь стал частью набора инструментов для создания сервисов сетевых приложений с высокой степенью параллелизма. Почему Node.js стал любимцем публики? Эта статья начнется с основных понятий процессов, потоков, сопрограмм и моделей ввода-вывода и даст вам всестороннее введение в Node.js и модель параллелизма.
Обычно мы называем выполняющийся экземпляр программы процессом. Это базовая единица распределения ресурсов и планирования операционной системой. Обычно он включает в себя следующие части:
进程表. Каждый процесс занимает进程表项(также называемую进程控制块). Эта запись содержит важный статус процесса, такой как счетчик программы, указатель стека, распределение памяти, состояние открытых файлов и информацию о планировании. . Информация, гарантирующая, что после приостановки процесса операционная система сможет правильно возобновить его.Процесс имеет следующие характеристики:
Следует отметить, что если программа запускается дважды, даже если операционная система может разрешить им совместно использовать код (т. е. только одна копия кода находится в памяти), она не может изменить то, что два экземпляра запущенной программы являются двумя разными. обрабатывает факт.
Во время выполнения процесса по различным причинам, таким как прерывания и планирование ЦП, процесс будет переключаться между следующими состояниями:

Из диаграммы переключения состояний процесса, приведенной выше, мы видим, что процесс может переключаться из рабочего состояния в состояние готовности и состояние блокировки, но только состояние готовности может быть напрямую переключено в состояние работы. Это происходит потому, что:
Иногда нам необходимо использовать потоки для решения следующих проблем:
Что касается потоков, нам необходимо знать следующие моменты:
Теперь, когда мы понимаем основные характеристики потоков, давайте поговорим о нескольких распространенных типах потоков.
Потоки состояния ядра — это потоки, напрямую поддерживаемые операционной системой. Его основные особенности заключаются в следующем:
Потоки пользовательского режима — это потоки, полностью встроенные в пользовательское пространство. Его основные характеристики заключаются в следующем:
Облегченный процесс (LWP) — это пользовательский поток, созданный и поддерживаемый ядром. Его основные особенности заключаются в следующем:
Пользовательское пространство может использовать потоки ядра только через облегченные процессы (LWP). мост между потоками пользовательского режима и потоками ядра. Следовательно, только при поддержке потоков ядра может существовать облегченный процесс (LWP).
Большинство операций облегченных процессов (LWP) требуют пространства пользовательского режима для инициации системного вызова. является относительно дорогим (требует переключения между пользовательским режимом и режимом ядра);
каждый облегченный процесс (LWP) должен быть связан с конкретным потоком ядра, поэтому:
они могут получить доступ к своим собственным процессам, ко всем общим адресным пространствам и системным ресурсам;
Выше мы кратко представили общие типы потоков (потоки состояния ядра, потоки состояния пользователя, облегченные процессы). Каждый из них имеет свою собственную область применения. При фактическом использовании вы можете свободно использовать их в соответствии со своими потребностями. комбинации, такие как обычные модели «один-к-одному», «многие-к-одному», «многие-ко-многим» и другие. Из-за ограниченности места в этой статье не будет представлено слишком много информации об этом. Заинтересованные студенты могут изучить ее самостоятельно.
, также называемый Fiber, представляет собой механизм запуска программ, построенный на потоках, который позволяет разработчикам самостоятельно управлять планированием выполнения, обслуживанием состояния и другими функциями:
В JavaScript async/await , который мы часто используем, является реализацией сопрограммы, как в следующем примере:
function updateUserName(id, name) {
константный пользователь = getUserById (id);
user.updateName(имя);
вернуть истину;
}
асинхронная функция updateUserNameAsync(id, name) {
константный пользователь = ждут getUserById (идентификатор);
ожидайте user.updateName(имя);
вернуть истину;
} В приведенном выше примере логическая последовательность выполнения функций updateUserName и updateUserNameAsync такова:
getUserById и присвоить ее возвращаемое значение переменной user ;updateName user ;true вызывающей стороне;Основное различие между ними заключается в контроле состояния во время фактической работы:
updateUserName она выполняется последовательно в соответствии с упомянутой выше логической последовательностью,updateUserNameAsync она также выполняется последовательно в соответствии с; логическая последовательность, упомянутая выше, но при обнаружении await updateUserNameAsync будет приостановлена и сохранит текущее состояние программы в приостановленном месте. updateUserNameAsync не будет снова активироваться до тех пор, пока фрагмент программы после await не вернется и не восстановит состояние программы перед приостановкой. а затем перейдите к следующей программе.Из приведенного выше анализа мы можем смело догадаться: то, что должны решать сопрограммы, — это не проблемы параллелизма программ, которые должны решать процессы и потоки, а проблемы, возникающие при обработке асинхронных задач (таких как файловые операции, сетевые запросы и т. д.); До появления async/await мы могли обрабатывать асинхронные задачи только с помощью функций обратного вызова, что могло легко привести к тому, что мы попали в回调地狱и создали беспорядок в коде, который обычно трудно поддерживать. С помощью сопрограмм мы можем добиться синхронизации асинхронного кода. .
Что необходимо иметь в виду, так это то, что основная возможность сопрограмм заключается в том, чтобы иметь возможность приостанавливать определенную программу и поддерживать состояние позиции приостановки программы, а также возобновлять ее в позиции приостановки в какой-то момент в будущем и продолжать работу. выполнить следующий сегмент после программы приостановки.
Полная операция I/O должна пройти следующие этапы:
I/O ядру посредством системного вызова,I/O (разделенный)Мы можем грубо разделить операции I/O на четыре типа:阻塞I/O ,非阻塞I/O ,同步I/O и异步I/O Прежде чем обсуждать эти типы, мы сначала познакомимся со следующими двумя наборами операций. понятия (здесь предположим, что сервис A вызывает сервис B):
阻塞/非阻塞:
阻塞调用,非阻塞调用.同步/异步:
同步;回调после завершения выполнения; Результат сообщается A, тогда служба B становится异步.Многие люди часто путают阻塞/非阻塞с同步/异步, поэтому необходимо уделять особое внимание:
阻塞/非阻塞— для调用者сервиса;同步/异步— для被调用者сервиса;Разобравшись阻塞/非阻塞и同步/异步, давайте посмотрим на конкретную I/O 模型.
: после того, как пользовательский поток инициирует системный вызов I/O , пользовательский поток будет немедленно阻塞до тех пор, пока не будет обработана вся операция I/O и результат не будет возвращен в пользовательский поток. Только после того, как пользователь войдет в поток. (поток) процесс может выйти из состояния阻塞и продолжить выполнение последующих операций.
Особенности:
I/O , пользовательский (поточный) процесс не может выполнять другие операции,I/O может заблокировать входящий (поток) поток, поэтому для того, чтобы вовремя ответить на запрос I/O , необходимо выделить входящий (поток) поток для каждого запроса, что приведет к огромному ресурсу использование, а также для длинных запросов на соединение, поскольку входящие (потоковые) ресурсы не могут быть освобождены в течение длительного времени, если в будущем появятся новые запросы, возникнет серьезное узкое место в производительности.Определение
I/O в потоке (потоке), если операция I/O не готова, вызов I/O вернет ошибку, и пользователь не необходимо войти в поток (поток). Подождите, но используйте опрос, чтобы определить, готова ли операция I/O ,I/O заблокирует поток пользователя до тех пор, пока результат выполнения не будет возвращен в потокОсобенности:
I/O (обычно с использованием цикла while ), модель должна занимать ЦП и потреблять ресурсы ЦП,I/O будет готова, пользовательI/O будет готова, последующие фактические операции I/O будут блокировать вход пользователя в поток (поток).Если после того, как пользовательский процесс (поток) инициирует системный вызов I/O , вызов I/O приводит к блокировке пользовательского процесса (потока), тогда вызов I/O является同步I/O , в противном случае это异步I/O .
Критерием определения того, является ли операция I/O同步или异步, является механизм связи между пользовательскими потоками и операциями I/O . В
同步взаимодействие между пользовательскими потоками и I/O синхронизируется через буфер ядра. то есть ядро синхронизирует результаты выполнения операции I/O с буфером, а затем копирует данные из буфера в пользовательский поток. Этот процесс блокирует пользовательский поток до тех пор, пока операция I/O не завершится异步I/O напрямую синхронизируется через ядро, то есть ядро напрямую копирует результаты выполнения операции I/O в пользовательский поток (поток). не блокировать пользовательский (поток) процесс.Node.js использует однопоточную модель асинхронного ввода I/O , управляемую событиями. Лично я считаю, что причина выбора этой модели заключается в следующем:
I/O . Как разумно и эффективно управлять многопоточными ресурсами, обеспечивая при этом высокий уровень параллелизма, сложнее, чем управление однопоточными ресурсами.Короче говоря, в целях простоты и эффективности Node.js использует однопоточную модель асинхронного I/O , управляемую событиями, и реализует ее через EventLoop основного потока и вспомогательного рабочего потока:
Следует отметить, что Node.js не подходит для выполнения задач с интенсивным использованием ЦП (т. е. требующих большого количества вычислений); это связано с тем, что код EventLoop и JavaScript (код неасинхронной задачи обработки событий) выполняются в одном потоке (т. е. основной поток), и любой из них. Если один из них работает слишком долго, это может привести к блокировке основного потока. Если приложение содержит большое количество задач, требующих длительного выполнения, это снизит пропускную способность сервера и может даже привести к его блокировке. привести к тому, что сервер перестанет отвечать на запросы.
Node.js — это технология, с которой фронтенд-разработчикам придется столкнуться сейчас и даже в будущем. Однако большинство фронтенд-разработчиков имеют лишь поверхностные знания о Node.js, чтобы каждый мог лучше понять модель параллелизма Node. .js. В этой статье сначала представлены процессы, потоки и сопрограммы, затем представлены различные модели I/O и, наконец, дается краткое введение в модель параллелизма Node.js. Хотя здесь не так уж много места для представления модели параллелизма Node.js, автор считает, что ее невозможно отделить от основных принципов. Освоение соответствующих основ и последующее глубокое понимание проектирования и реализации Node.js позволят получить вдвое больший результат. с половиной усилий.
Наконец, если в этой статье есть какие-либо ошибки, я надеюсь, что вы сможете их исправить. Желаю всем вам счастливого программирования каждый день.