Статьи

Введение в HTML5 Web Workers: многопоточный подход JavaScript

Приложение HTML5 явно написано с использованием JavaScript. Но по сравнению с другими типами сред разработки (например, нативными) JavaScript исторически имеет важное ограничение: весь процесс его выполнения остается внутри уникального потока . Это может быть довольно раздражающим в современных многоядерных процессорах, таких как i5 / i7, содержащих до 8 логических процессоров, и даже в том, что последние мобильные процессоры ARM являются двухъядерными или даже четырехъядерными. Надеемся, что мы увидим, что HTML5 предлагает в Интернете способ лучше справляться с этими новыми чудесными процессорами, чтобы помочь вам охватить новое поколение веб-приложений.

Иллюстрация: веб-работники в действии

Выступление на высочайшем уровне по языку Мольера, посвященному новой версии: Введение в Web Workers d’HTML5: многопоточная версия JavaScript

Перед рабочими …

Это ограничение JavaScript подразумевает, что длительная обработка остановит главное окно. Мы часто говорим словами наших разработчиков, что мы блокируем « поток пользовательского интерфейса ». Это основной поток, отвечающий за обработку всех визуальных элементов и связанных задач: рисование, обновление, анимация, события пользовательского ввода и т. Д. Все мы знаем о плохих последствиях перегрузки этого потока: страница зависает, и пользователь не может взаимодействовать больше с вашим приложением. Пользовательский опыт тогда, конечно, очень плох, и пользователь, вероятно, решит убрать вкладку или экземпляр браузера. Это, вероятно, не то, что вы хотели бы видеть при использовании вашего приложения!

Чтобы избежать этого, в браузерах реализован механизм защиты, который предупреждает пользователя, когда возникает длительный подозрительный сценарий. К сожалению, этот механизм защиты не может сделать разницу между скриптом, написанным неправильно, и скриптом, которому действительно нужно больше времени для выполнения своей работы. Тем не менее, поскольку он блокирует поток пользовательского интерфейса, лучше сообщить вам, что в настоящее время, возможно, происходит что-то не так. Вот несколько примеров сообщений (из Firefox 5 и IE9):

ProtectionJSFF5

20110419-hrii-image5

Надеемся, что до сих пор эти проблемы возникали редко по двум основным причинам:

1 — HTML и JavaScript не использовались таким же образом и для тех же целей, что и другие технологии, способные решать многопоточные задачи. Веб-сайты предлагали пользователям больше возможностей, чем нативные приложения.
2 — Существовали и другие способы более или менее решить эту проблему параллелизма.

Эти способы хорошо известны всем веб-разработчикам. Мы действительно пытались имитировать параллельные задачи, например, с помощью методов setTimeout () и setInterval () . HTTP-запросы также могут выполняться асинхронно благодаря объекту XMLHttpRequest, который предотвращает зависание пользовательского интерфейса при загрузке некоторых ресурсов с некоторых удаленных серверов. Наконец, события DOM позволяют нам писать приложения, создавая иллюзию, что несколько вещей происходят одновременно. Иллюзия, правда? Да!

Чтобы лучше понять почему, давайте посмотрим на фальшивый кусок кода и посмотрим, что происходит внутри браузера:

<script type="text/javascript">
    function init(){
        { piece of code taking 5ms to be executed } 
        A mouseClickEvent is raised
        { piece of code taking 5ms to be executed }
        setInterval(timerTask,"10");
        { piece of code taking 5ms to be executed }
    }

    function handleMouseClick(){
          piece of code taking 8ms to be executed 
    }

    function timerTask(){
          piece of code taking 2ms to be executed 
    }
</script> 

Давайте возьмем этот код, чтобы спроецировать его на модель. Затем эта диаграмма показывает нам, что происходит в браузере в масштабе времени:

Диаграмма, иллюстрирующая однопоточный JavaScript

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

— от 0 до 5 мс: функция init () запускается задачей 5 мс. Через 5 мс пользователь вызывает событие щелчка мышью. Однако это событие не может быть обработано прямо сейчас, так как мы все еще выполняем функцию init (), которая в настоящее время монополизирует основной поток. Событие click сохраняется и будет обработано позже.

— от 5 до 10 мс: функция init () продолжает свою обработку в течение 5 мс, а затем просит запланировать вызов функции timerTask () в течение 10 мс. Эта функция должна затем логически выполняться на 20 мсек.

— от 10 до 15 мсек: 5 новых миллисекунд необходимо, чтобы завершить полный запуск функции init () . Это тогда соответствует 15 мс желтого блока. Поскольку мы освобождаем основной поток, он теперь может начать удалять сохраненные запросы.

— от 15 до 23 мс: браузер запускается с помощью события handleMouseClock (), которое выполняется в течение 8 мс (синий блок).

— от 23 до 25 мс: в качестве побочного эффекта функция timerTask (), которую планировалось запустить на таймфрейме 20 мс, слегка смещена на 3 мс. Другие запланированные кадры (30 мс, 40 мс и т. Д.) Соблюдаются, поскольку больше нет кода, занимающего некоторый процессор.

Примечание: этот образец и приведенная выше диаграмма (в SVG или PNG с помощью механизма обнаружения функций) были вдохновлены следующей статьей: Многопоточность в Web5 для веб-работников HTML5

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

Более того, даже если в прошлом JavaScript не использовался для приложений того же типа, что и так называемые «языки высокого уровня», он начинает меняться, наконец, благодаря новым возможностям, предлагаемым HTML5 и его друзьями. Тогда было более чем важно предоставить JavaScript некоторые новые возможности, чтобы он был готов к созданию приложений нового поколения, способных использовать параллельные задачи. Это именно то, для чего были созданы веб-работники.

Веб-работники или как выполнить из потока пользовательского интерфейса

В Web Workers API , определяет способ запуска сценария в фоновом режиме. После этого мы сможем выполнять некоторые задачи в потоках, которые находятся за пределами главной страницы и, таким образом, не влияют на производительность рисования. Однако точно так же, как мы знаем, что не все алгоритмы могут быть распараллелены, не весь код JavaScript может использовать преимущества рабочих. Хорошо, хватит, бла-бла, давайте посмотрим на этих знаменитых работников.

Мой первый веб-работник

Поскольку Web Workers будут выполняться в отдельных потоках, вам нужно разместить их код в отдельных файлах с главной страницы. После этого вам нужно создать экземпляр объекта Worker для их вызова:

var myHelloWorker = new Worker('helloworkers.js');

Затем вы запустите рабочий (и, следовательно, поток под Windows), отправив ему первое сообщение:

myHelloWorker.postMessage();

Действительно, веб-работники и главная страница общаются через сообщения. Эти сообщения могут быть сформированы с помощью обычных строк или объектов JSON. Чтобы проиллюстрировать простую публикацию сообщений, мы начнем с обзора очень простого примера. Он отправит строку работнику, который просто объединит ее с чем-то другим. Для этого добавьте следующий код в файл helloworker.js :

function messageHandler(event) {
    // Accessing to the message data sent by the main page
    var messageSent = event.data;
    // Preparing the message that we will send back
    var messageReturned = "Hello " + messageSent + " from a separate thread!";
    // Posting back the message to the main page
    this.postMessage(messageReturned);
}

// Defining the callback function raised when the main page will call us
this.addEventListener('message', messageHandler, false);

Мы только что определили внутри « helloworkers.js » кусок кода, который будет выполняться в другом потоке. Он может получать сообщения с вашей главной страницы, выполнять некоторые задачи и отправлять сообщения обратно на вашу страницу в ответ. Затем нам нужно написать получателя на главной странице. Вот страница, которая будет обрабатывать это:

<!DOCTYPE html>
<html>
<head>
    <title>Hello Web Workers</title>
</head>
<body>
    <div id="output"></div>

    <script type="text/javascript">
        // Instantiating the Worker
        var myHelloWorker = new Worker('helloworkers.js');
        // Getting ready to handle the message sent back
        // by the worker
        myHelloWorker.addEventListener("message", function (event) {
            document.getElementById("output").textContent = event.data;
        }, false);

        // Starting the worker by sending a first message
        myHelloWorker.postMessage("David");

        // Stopping the worker via the terminate() command
        myHelloWorker.terminate();
    </script>
</body>
</html>

Результатом будет: « Привет, Дэвид из отдельного потока! ». Вы сейчас впечатлены, не так ли?Clignement d'œil

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

1 — с главной страницы вызова, вызвав команду terminate () .
2 — от самого работника с помощью команды close () .

ДЕМО : Вы можете протестировать этот слегка улучшенный пример в своем браузере здесь ->http://david.blob.core.windows.net/html5/HelloWebWorkers_EN.htm<-

Публикация сообщений с использованием JSON

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

Но единственный способ отправить некоторые структурированные сообщения работнику — это использовать формат JSON. Надеемся, что браузеры, которые в настоящее время поддерживают Web Workers, достаточно хороши, чтобы также изначально поддерживать JSON. Как они добры!

Давайте тогда возьмем наш предыдущий пример кода. Мы собираемся добавить объект типа WorkerMessage. Этот тип будет использоваться для отправки некоторых команд с параметрами нашим веб-работникам.

Давайте теперь используем следующую упрощенную веб-страницу HelloWebWorkersJSON_EN.htm :

<!DOCTYPE html>
<html>
<head>
    <title>Hello Web Workers JSON</title>
</head>
<body>
    <input id=inputForWorker /><button id=btnSubmit>Send to the worker</button><button id=killWorker>Stop the worker</button>
    <div id="output"></div>

    <script src="HelloWebWorkersJSON.js" type="text/javascript"></script>
</body>
</html>

Здесь мы используем ненавязчивый подход JavaScript, который помогает нам отделить представление от присоединенной логики. Прикрепленная логика живет в этом файле HelloWebWorkersJSON_EN.js :

// HelloWebWorkersJSON_EN.js associated to HelloWebWorkersJSON_EN.htm

// Our WorkerMessage object will be automatically
// serialized and de-serialized by the native JSON parser
function WorkerMessage(cmd, parameter) {
    this.cmd = cmd;
    this.parameter = parameter;
}

// Output div where the messages sent back by the worker will be displayed
var _output = document.getElementById("output");

/* Checking if Web Workers are supported by the browser */
if (window.Worker) {
    // Getting references to the 3 other HTML elements
    var _btnSubmit = document.getElementById("btnSubmit");
    var _inputForWorker = document.getElementById("inputForWorker");
    var _killWorker = document.getElementById("killWorker");

    // Instantiating the Worker
    var myHelloWorker = new Worker('helloworkersJSON_EN.js');
    // Getting ready to handle the message sent back
    // by the worker
    myHelloWorker.addEventListener("message", function (event) {
        _output.textContent = event.data;
    }, false);

    // Starting the worker by sending it the 'init' command
    myHelloWorker.postMessage(new WorkerMessage('init', null));

    // Adding the OnClick event to the Submit button
    // which will send some messages to the worker
    _btnSubmit.addEventListener("click", function (event) {
        // We're now sending messages via the 'hello' command 
        myHelloWorker.postMessage(new WorkerMessage('hello', _inputForWorker.value));
    }, false);

    // Adding the OnClick event to the Kill button
    // which will stop the worker. It won't be usable anymore after that.
    _killWorker.addEventListener("click", function (event) {
        // Stopping the worker via the terminate() command
        myHelloWorker.terminate();
        _output.textContent = "The worker has been stopped.";
    }, false);
}
else {
    _output.innerHTML = "Web Workers are not supported by your browser. Try with IE10: <a href=\"http://ie.microsoft.com/testdrive\">download the latest IE10 Platform Preview</a>";
}

Наконец, вот код для веб-работника, содержащийся в файле helloworkerJSON_EN.js :

function messageHandler(event) {
    // Accessing to the message data sent by the main page
    var messageSent = event.data;

    // Testing the command sent by the main page
    switch (messageSent.cmd) {
        case 'init':
            // You can initialize here some of your models/objects
            // that will be used later on in the worker (but pay attention to the scope!)
            break;
        case 'hello':
            // Preparing the message that we will send back
            var messageReturned = "Hello " + messageSent.parameter + " from a separate thread!";
            // Posting back the message to the main page
            this.postMessage(messageReturned);
            break;
    }
}

// Defining the callback function raised when the main page will call us
this.addEventListener('message', messageHandler, false);

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

ДЕМО : Вы можете проверить этот пример JSON здесь: ->http://david.blob.core.windows.net/html5/HelloWebWorkersJSON_EN.htm<-

Поддержка браузеров browserslogos

Веб-работники только что прибыли в IE10 PP2 (предварительный просмотр платформы) . Это также поддерживается Firefox (начиная с версии 3.6), Safari (начиная с версии 4.0), Chrome & Opera 11. Однако это не поддерживается мобильными версиями этих браузеров. Если вы хотите получить более подробную матрицу поддержки, загляните сюда: http://caniuse.com/#search=worker

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

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

/* Checking if Web Workers are supported by the browser */
if (window.Worker) {
    // Code using the Web Workers
}

Второй — использовать знаменитую библиотеку Modernizr (теперь она поставляется с шаблонами проектов ASP.NET MVC3). Затем просто используйте такой код:

<script type="text/javascript">
    var divWebWorker = document.getElementById("webWorkers");
    if (Modernizr.webworkers) {
        divWebWorker.innerHTML = "Web Workers ARE supported";
    }
    else {
        divWebWorker.innerHTML = "Web Workers ARE NOT supported";
    }
</script>

Вот, например , текущая поддержка в браузере: Web Workers которые поддерживаются в вашем браузере.

Это позволит вам выставить 2 версии вашего приложения. Если Web Workers будут не поддерживается, вы просто выполнить свой код JavaScript , как обычно. Если Web Workers будут поддержаны, вы будете в состоянии выдвинуть некоторые из кода JavaScript для рабочих , чтобы повысить производительность приложений для самых последних версиях браузеров. Тогда вы ничего не сломаете и не создадите конкретную версию только для самых последних браузеров. Это будет работать для всех браузеров с некоторыми различиями в производительности.

Недоступные элементы от работника

Вместо того , чтобы смотреть на то , что вы не имеете доступа от работников, давайте скорее посмотрим на то , что вы только иметь доступ. Для этого, пожалуйста, проверьте таблицу из нашей документации MSDN: HTML5 Web Worker

Но короткая версия: у вас нет доступа к DOM .

В Web Workers в IE10: Фоновая JavaScript Делает Web Apps Faster статьи из нашего блога IE была очень хорошая схема подытожив , что:

20110701-wwiibjmwaf-image2

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

Обработка ошибок и отладка

Очень легко обрабатывать ошибки, возникающие у ваших веб-работников. Вы просто должны подписаться на событие OnError так же, как мы сделали это с событием OnMessage :

myWorker.addEventListener("error", function (event) {
    _output.textContent = event.data;
}, false);

Это лучшее, что веб-работники могут вам дать, чтобы помочь в отладке их кода … Это очень ограниченно, не так ли?

Панель разработки F12 для лучшего опыта отладки

Чтобы пойти дальше, IE10 предлагает вам непосредственно отладить код ваших веб-работников внутри своего отладчика сценариев, как и любой другой сценарий.

Для этого вам нужно запустить панель разработки с помощью клавиши F12 и перейти на вкладку « Сценарий ». Вы еще не должны видеть файл JS, связанный с вашим работником. Но сразу после нажатия кнопки « Начать отладку » она должна волшебным образом отображаться:

F12DebugWorker001

Следующим шагом является просто отладка вашего работника, как вы привыкли отлаживать свой классический код JavaScript!

DebugWebWorkersF12

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

Интересное решение для имитации console.log ()

Наконец, вам нужно знать, что консольный объект недоступен внутри рабочего. Таким образом, если вам нужно отследить, что происходит внутри рабочего, с помощью метода .log () , он не будет работать, так как консольный объект не будет определен. Надеюсь, я нашел интересный пример, который имитирует поведение console.log () с помощью MessageChannel : console.log () для веб-работников . Это хорошо работает в IE10, Chrome и Opera, но не в Firefox, поскольку еще не поддерживает MessageChannel .

Примечание: для того, чтобы пример из этой ссылки работал нормально в IE10, вам нужно изменить эту строку кода:

console.log.apply(console, args); // Pass the args to the real log

Этим:

console.log(args); // Pass the args to the real log

Тогда вы сможете получить такие результаты:

DebugWebWorkersF12Console

ДЕМО : Если вы хотите попробовать этомоделированиеconsole.log (): ->http://david.blob.core.windows.net/html5/HelloWebWorkersJSONdebug_EN.htm<-

Примеры использования и как определить потенциальных кандидатов

Веб-работники для каких сценариев?

Когда вы просматриваете веб-сайты в поисках примеров использования Web Workers, вы всегда найдете один и тот же вид демонстраций: интенсивные математические / научные вычисления. Затем вы найдете некоторые трассировщики JavaScript, фракталы, простые числа и тому подобное. Хорошие демонстрации, чтобы понять, как работают работники, но это дает нам несколько конкретных перспектив о том, как использовать их в приложениях «реального мира».

Это правда, что ограничения, которые мы видели выше в отношении ресурсов, доступных внутри веб-работников, сужают количество интересных сценариев. Тем не менее, если вы просто подумаете об этом, вы начнете видеть новые интересные способы использования:

обработка изображений с использованием данных, извлеченных из элементов <canvas> или <video>. Вы можете разделить изображение на несколько зон и передать их различным рабочим, которые будут работать параллельно. Тогда вы получите выгоду от нового поколения многоядерных процессоров. Чем больше у вас есть, тем быстрее вы пойдете.
получено большое количество данных , которые необходимо проанализировать после вызова XMLHTTPRequest. Если время, необходимое для обработки этих данных, важно, лучше сделать это в фоновом режиме внутри веб-работника, чтобы избежать зависания потока пользовательского интерфейса. Затем вы сохраните реактивную заявку.
фоновый анализ текста: поскольку у нас есть потенциально больше процессорного времени при использовании веб-работников, теперь мы можем подумать о новых сценариях в JavaScript. Например, мы могли бы представить в режиме реального времени анализ того, что пользователь печатает в данный момент, не влияя на работу пользовательского интерфейса. Подумайте о приложении, таком как Word (из нашего пакета Office Web Apps), использующем такую ​​возможность: фоновый поиск в словарях, помогающий пользователю при наборе текста, автоматическое исправление и т. Д.
одновременные запросы к локальной базе данных . IndexDB позволит то, что локальное хранилище не может предложить нам: многопоточную среду хранения для наших веб-работников

Более того, если вы переключитесь на мир видеоигр, вы можете подумать о том, чтобы подтолкнуть AI или физические движки к Web Workers. Например, я нашел этот эксперимент: на Web Workers, GWT и демонстрации New Physics, которые используют физический движок Box2D с работниками. Для вашего движка искусственного интеллекта это также означает, что вы сможете в одно и то же время обрабатывать больше данных (например, предвидеть больше ходов в шахматной игре).

Некоторые из моих коллег могут теперь утверждать, что единственным ограничением является ваше воображение! Tire la langue

Но в целом, если вам не нужен DOM, любой JavaScript-код, который может повлиять на работу пользователя, является хорошим кандидатом для веб-работников. Однако при использовании рабочих необходимо обратить внимание на 3 пункта:

1 — Время инициализации и время связи с рабочим не должны быть выше самой обработки.
2 — Стоимость памяти при использовании нескольких рабочих.
3 — Зависимость блоков кода между ними, так как вам может потребоваться некоторая логика синхронизации. Распараллеливание это не просто, друзья!

Со своей стороны, мы недавно опубликовали демо-версию под названием Web Workers Fountains :

Веб работники фонтаны

Эта демонстрация отображает некоторые эффекты частиц (фонтаны) и использует 1 веб-работника на фонтан, чтобы попытаться вычислить частицы самым быстрым способом. Затем каждый рабочий результат агрегируется для отображения внутри элемента <canvas>. Веб-работники могут также обмениваться сообщениями между ними через каналы сообщений . В этой демонстрации это используется, чтобы спросить каждого из рабочих, когда менять цвет фонтанов. Затем мы перебираем множество цветов: красный, оранжевый, желтый, зеленый, синий, фиолетовый и розовый благодаря каналам сообщений. Если вам интересно узнать подробности, перейдите в функцию LightManager () файла Demo3.js .

Не стесняйтесь также запускать эту демонстрацию в Internet Explorer 10 , с ней забавно играть!Sourire

Как определить горячие точки в вашем коде

Чтобы отследить узкие места и определить, какие части вашего кода вы могли бы отправить веб-работникам, вы можете использовать профилировщик сценариев, доступный с панелью F12 IE9 / 10. Затем он поможет вам определить ваши горячие точки. Однако определение горячей точки не означает, что вы нашли подходящего кандидата для веб-работников. Чтобы лучше это понять, давайте вместе рассмотрим 2 разных интересных случая.

Случай 1: анимация <canvas> с демонстрацией Speed ​​Reading

Эта демонстрация взята из нашего центра IE Test Drive и доступна для просмотра прямо здесь: Speed ​​Reading . Он пытается максимально быстро отобразить некоторые символы, используя элемент <canvas>. Цель состоит в том, чтобы подчеркнуть качество реализации аппаратного ускорения слоя вашего браузера. Но, выйдя за пределы этого, можно ли добиться большей производительности, разделив некоторые операции на потоки? Нам нужно провести некоторый анализ, чтобы проверить это.

Если вы запустите эту демонстрацию в IE9 / 10, вы также можете запустить профилировщик в течение нескольких секунд. Вот такие результаты вы получите:

ProfilingF12SpeedReading

Если вы сортируете трудоемкие функции в порядке убывания, вы четко увидите, что эти функции идут первыми: DrawLoop () , Draw () и drawImage () . Если вы дважды щелкнете по линии Draw , вы попадете в код этого метода. Затем вы увидите несколько вызовов этого типа:

surface.drawImage(imgTile, 0, 0, 70, 100, this.left, this.top, this.width, this.height); 

Где объект поверхности ссылается на элемент <canvas>.

Быстрый вывод этого краткого анализа состоит в том, что эта демонстрация проводит большую часть своего времени в рисовании внутри Canvas с помощью метода drawImage () . Поскольку элемент <canvas> недоступен веб-работнику, мы не сможем переложить эту трудоемкую задачу на разные потоки (например, мы могли бы представить некоторые способы обработки элемента <canvas> в параллельном режиме) , Эта демонстрация не является хорошим кандидатом на возможности распараллеливания, предлагаемые веб-работниками.

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

Случай 2: Raytracers внутри <canvas>

Давайте теперь возьмем другой простой пример для понимания. Давайте возьмем raytracer, как этот: Flog.RayTracer Canvas Demo . Raytracer использует некоторые очень интенсивные математические вычисления, чтобы моделировать путь света . Идея состоит в том, чтобы моделировать некоторые эффекты, такие как отражение, преломление, материалы и т. Д.

Давайте визуализируем сцену при запуске скриптового профилировщика, вы должны получить что-то вроде этого:

ProfilingF12RayTracer

Опять же, если мы сортируем функции в порядке убывания, очевидно, что 2 функции занимают большую часть времени: renderScene () и getPixelColor ().

Цель метода getPixelColor () — вычислить текущий пиксель. В самом деле, трассировка лучей отображает пиксель сцены на пиксель. Этот метод getPixelColor () затем вызывает метод rayTrace (), отвечающий за рендеринг теней, окружающего света и т. Д. Это ядро ​​нашего приложения. И если вы просматриваете код rayTrace ()функция, вы увидите, что это 100% чистый сок JavaScript. Этот код не имеет зависимости DOM. Ну, я думаю, вы поймете: этот пример — очень хороший кандидат на распараллеливание. Более того, мы можем легко разделить рендеринг изображения на несколько потоков (и, следовательно, потенциально на несколько процессоров), поскольку не требуется синхронизация между вычислениями каждого пикселя. Каждая пиксельная операция не зависит от своего соседства, так как в этой демонстрации не используется сглаживание.

Это не удивительно, если мы можем найти некоторые образцы raytracers, используя таких веб-работников, как этот: http://nerget.com/rayjs-mt/rayjs.html

После профилирования этого raytracer с использованием IE10, мы можем увидеть важные различия между использованием без работника и использованием четырех работников:

RayTracersWebWorkersIE10

На первом снимке экрана метод processRenderCommand () использует почти все доступные ресурсы ЦП, а сцена отображается в 2.854 с .

С 4 веб-работниками метод processRenderCommand () выполняется параллельно в 4 разных потоках. Мы даже можем увидеть их Worker Id в правом столбце. Сцена отрисована на этот раз в 1.473 . Преимущества были реальными: сцена была визуализирована в 2 раза быстрее.

Вывод

Не существует магических или новых концепций, связанных с веб-работниками, которые бы анализировали / разрабатывали ваш код JavaScript для параллельного выполнения. Вам необходимо выделить интенсивную часть вашего кода. Он должен быть относительно независимым от остальной логики вашей страницы, чтобы избежать ожидания задач синхронизации. И самая важная часть: код не должен быть связан с DOM. Если все эти условия соблюдены, подумайте о веб-работниках. Они определенно могут помочь вам повысить общую производительность вашего веб-приложения!

Дэвид

PS: Все образцы этой статьи доступны в этом ZIP-файле: https://david.blob.core.windows.net/html5/WebWorkersSamples.zip .

 

Источник: http://blogs.msdn.com/b/davrous/archive/2011/07/15/introduction-to-the-html5-web-workers-the-javascript-multithreading-approach.aspx