В традиционных модулях программирования операции ввода -вывода похожи на обычный локальный вызов функции: программа заблокирована до выполнения функции и не может продолжать работать. Заблокированный ввод/вывод возник из более ранней модели среза, где каждый процесс похож на независимого человека, с целью различения всех, и каждый обычно может делать только одну вещь одновременно, и должен ждать предыдущей вещи, прежде чем решить, что делать дальше. Тем не менее, эта модель «Один пользователь, один процесс», который широко используется в компьютерных сетях и интернете, очень масштабируется. При управлении несколькими процессами он потребляет много памяти, и переключение контекста также будет занимать много ресурсов. Это огромное бремя для операционной системы, и по мере увеличения количества процессов производительность системы резко распадается.
Многопользовательский режим - альтернатива. Поток - это легкий процесс, который разделяет память с другими потоками в том же процессе. Это больше похоже на расширение традиционной модели, которая используется для одновременного выполнения нескольких потоков. Когда один поток ждет операций ввода -вывода, другие потоки могут захватить процессор. Когда операция ввода/вывода будет завершена, поток, ожидающая впереди, будет пробуждена. То есть, работающая поток может быть прерван, а затем возобновлена позже. Кроме того, потоки могут работать параллельно под разными ядрами многоядерных процессоров в некоторых системах.
Программисты не знают, в какое время поток будет работать. Они должны быть осторожны, чтобы обрабатывать одновременный доступ к общей памяти, поэтому они должны использовать некоторые примитивы синхронизации для синхронизации доступа к определенной структуре данных, например, использование замков или семафоры, чтобы заставить потоки выполнять в определенных поведениях и планах. Приложения, которые в значительной степени зависят от общего состояния между потоками, могут легко иметь некоторые странные проблемы со сильной случайностью и трудностями в поиске.
Другой способ-использовать многопоточное сотрудничество, где вы несете ответственность за явное освобождение ЦП и передачу времени ЦП на другие потоки. Поскольку вы лично контролируете план выполнения потока, необходимость синхронизации уменьшается, но она также увеличивает сложность программы и вероятность ошибок и не избегает проблем многопоточного чтения.
Что такое программирование, управляемое событиями
Программирование, управляемое событиями,-это стиль программирования, где события определяют процесс выполнения программы. События обрабатываются обработчиками событий или обратными вызовами событий. Обратные вызовы событий - это функции, вызванные, когда происходит конкретное событие, например, база данных возвращает результат запроса или пользователь нажимает кнопку.
Напомним, что в традиционном блокированном режиме программирования ввода/вывода запросы базы данных могут выглядеть так:
Кода -копия выглядит следующим образом:
result = Query ('select * из постов, где id = 1');
do_something_with (result);
Приведенная выше функция запроса будет хранить текущий поток или процесс в состоянии ожидания, пока базовая база данных не завершит операцию запроса и вернется.
В модели, основанной на событиях, этот запрос станет таким:
Кода -копия выглядит следующим образом:
Query_finiend = function (result) {
do_something_with (result);
}
Query ('select * из постов, где id = 1', Query_finied);
Сначала вы определяете функцию, называемую Query_finiend, которая содержит то, что вы хотите сделать после завершения запроса. Затем передайте эту функцию в качестве параметра функции запроса. Query_finied будет вызван после выполнения запроса, вместо того, чтобы просто возвращать результат запроса.
Когда происходит событие, которое вас интересует, функция, которую вы определяете, будет вызвана вместо того, чтобы просто возвращать значение результата. Эта модель программирования называется программированием, управляемым событиями или асинхронным программированием. Это одна из самых очевидных особенностей узла. Эта модель программирования означает, что текущий процесс не будет заблокирован при выполнении операций ввода -вывода. Поэтому несколько операций ввода/вывода могут быть выполнены параллельно, а соответствующая функция обратного вызова будет вызвана после завершения операции.
Основной уровень программирования, управляемого событиями, зависит от петлей событий. Петли событий - это в основном структура, в которой процессор обнаружения и события выявляет события и вызывает непрерывный цикл этих двух функций. В каждом цикле механизм цикла событий должен определить, какие события произошли. Когда событие происходит, оно находит соответствующую функцию обратного вызова и вызывает ее.
Цикл событий - это всего лишь ветка, работающая в процессе. Когда происходит событие, процессор событий может работать в одиночку и не будет прерван, то есть:
1. Большая часть одной функции обратного вызова событий работает в определенный момент
2. Ни один процессор событий не прерывается при запуске
При этом разработчики больше не могут испытывать головные боли о синхронизации потоков и одновременной модификации общей памяти.
Известный секрет:
Давным-давно люди в сообществе системного программирования знали, что программирование, управляемое событиями, является лучшим способом создания высококачественных услуг параллелизма, потому что ему не нужно было сохранить много контекста, поэтому оно сохранило много памяти, а не так много контекстного переключения и сохранила много времени выполнения.
Медленно, эта концепция пронизывала другие платформы и сообщества, и появились некоторые знаменитые реализации цикла событий, такие как Machine Ruby's Event, Perl's Anyevnet и Python's Twisted. В дополнение к этому, есть много других реализаций и языков.
Чтобы разработать эти структуры, вам необходимо изучить конкретные знания, связанные с структурой и библиотеками классов, специфичных для основы. Например, при использовании событий, чтобы пользоваться преимуществами неблокировки, вы должны избегать использования синхронных классовых библиотек и можете использовать только асинхронные библиотеки классов событий. Если вы используете какую -либо библиотеку блокировки (например, большинство стандартной библиотеки Ruby), ваш сервер теряет оптимальную масштабируемость, поскольку цикл события все еще будет блокироваться постоянно, время от времени блокируя обработку событий ввода -вывода.
Узел был первоначально разработан как не блокирующая платформа ввода-вывода/вывода, поэтому в целом вы должны ожидать, что весь код, работающий на нем, не блокирует. Поскольку JavaScript очень мал и не заставляет ни одной модели ввода -вывода (поскольку у него нет стандартной библиотеки классов ввода/вывода), узел встроен в очень чистую среду, и не будет никаких устаревших проблем.
Как узел и JavaScript упрощают асинхронные приложения
Автор Узела Райан Дал первоначально использовал C для разработки этого проекта, но обнаружил, что контекст поддержания вызовов функций был слишком сложным, что привело к высокой сложности кода. Затем он переключился на Луа, но у Луа уже есть несколько блокирующих библиотек ввода -вывода. Смешивание блокировки и неблокировки может запутать разработчиков и, следовательно, предотвратить создание масштабируемых приложений. Поэтому Луа также был заброшен Даль. Наконец он обратился к JavaScript, закрытию в JavaScript и функциях объектов первого уровня, которые делают JavaScript очень подходящим для программирования, управляемого событиями. Магия JavaScript является одной из основных причин, по которой узел так популярен.
Что такое закрытие
Закрытие может быть понято как особая функция, но оно может наследовать и переменные доступа в прицеле, которую он определяется. Когда вы передаете функцию обратного вызова в качестве параметра другой функции, она будет вызвана позже. Магия заключается в том, что когда эта функция обратного вызовов называется позже, она фактически вспоминает контекст, в котором она определяет себя, и переменные в родительском контексте, а также может получить доступ к ним нормально. Эта мощная особенность является ядром успеха узла.
В следующем примере будет показано, как закрытия JavaScript работают в веб -браузере. Если вы хотите прослушать отдельное событие на кнопке, вы можете сделать это:
Кода -копия выглядит следующим образом:
var clickCount = 0;
document.getElementbyId ('mybutton'). onclick = function () {
ClickCount += 1;
ALERT («нажал» + clickCount + «Время».);
};
Так при использовании jQuery:
Кода -копия выглядит следующим образом:
var clickCount = 0;
$ ('кнопка#mybutton'). Click (function () {
ClickedCount ++;
Alert ('нажал' + clickcount + 'times.');
});
В JavaScript функции являются первым типом объектов, что означает, что вы можете передавать функции в качестве параметров в другие функции. В двух вышеупомянутых примерах первый назначает функцию другой функции, а вторая передает функцию в качестве параметра другой функции. Функция обработки событий Click (функция обратного вызова) может получить доступ к каждой переменной под блоком кода, где функция определяет ее. В этом примере он может получить доступ к переменной ClickCount, определенной в его родительском закрытии.
Переменная ClickCount находится в глобальной области (самая внешняя область в JavaScript), что сохраняет количество раз, когда пользователь нажимает кнопку. Обычно это плохая привычка хранить переменные в глобальном масштабе, потому что их легко конфликтовать с другим кодом, и вы должны поместить переменные в локальную область, где вы их используете. В большинстве случаев просто завершение кода одной функцией эквивалентно созданию другого закрытия, которое может легко избежать загрязнения глобальной среды, как это:
Кода -копия выглядит следующим образом:
(function () {
var clickCount = 0;
$ ('кнопка#mybutton'). Click (function () {
ClickCount ++;
Alert ('нажал' + clickcount + 'times.');
});
} ());
Примечание. Седьмая строка приведенного выше кода определяет функцию и немедленно вызывает ее. Это общий шаблон дизайна в JavaScript: создайте новую область, создав функцию.
Как закрытие помогает асинхронное программирование
В модели программирования, управляемой событиями, сначала напишите код для запуска после возникновения события, затем поместите код в функцию и, наконец, передайте функцию в качестве параметра вызывающему абоненту, а затем вызовите его функцией абонента позже.
В JavaScript функция не является изолированным определением. Это также помнит контекст объема, который он объявлен. Этот механизм позволяет функциям JavaScript получить доступ к контексту, в котором расположено определение функции, и все переменные в родительском контексте.
Когда вы передаете функцию обратного вызова в качестве параметра вызывающего абонента, функция будет вызвана в более поздней точке. Даже если область, определяющая функцию обратного вызова, закончилась, когда вызывается функция обратного вызова, он все равно может получить доступ ко всем переменным в окончательном объеме и его родительском масштабе. Как и в последнем примере, функция обратного вызова вызывает внутри Click () jQuery, но она все еще может получить доступ к переменной ClickCount.
Магия закрытия показана ранее. Передача переменных состояния в функцию позволяет вам выполнять программирование, управляемое событиями, не поддерживая состояния. Механизм закрытия JavaScript поможет вам сохранить их.
краткое содержание
Программирование, управляемое событиями,-это модель программирования, которая определяет процесс выполнения программы посредством запуска событий. Программисты регистрируют функции обратного вызова для событий, которые им интересны (обычно называемые обработчиками событий), и затем система вызывает зарегистрированное обработчик событий, когда происходит событие. Эта модель программирования имеет много преимуществ, которых не имеют традиционных моделей программирования блокировки. В прошлом для реализации аналогичных функций необходимо использовать многопроцесс/многопоточное.
JavaScript-это мощный язык из-за своего первого типа функции объекта и свойств закрытия, что делает его очень подходящим для программирования, управляемого событиями.