Бұл жазба автоматты түрде аударылған. Бастапқы тіл: Орысша
Әзірлеушілер ретінде біз әрқашан қосымшаның өнімділігін жақсарту мүмкіндіктерін іздейміз. Web қосымшасы туралы айтатын болсақ, біз негізінен кодты жақсартамыз.
Бірақ сіз өзіңіздің веб-қосымшаларыңыздағы GPU қуатын өнімділікті жақсарту үшін біріктіру туралы ойландыңыз ба?
Бұл мақала сізді GPU деп аталатын JavaScript жеделдету кітапханасымен таныстырады.js және күрделі есептеулерді қалай жақсартуға болатындығын көрсетеді.
***
GPU дегеніміз не.js және біз оны не үшін қолданамыз?
Дереккөз: https://gpu.rocks/#/
Қысқаша, GPU.js-JavaScript үдеткіш кітапханасы, оны JavaScript көмегімен GPU-де жалпы мақсатты есептеу үшін пайдалануға болады. Ол браузерлерде, Node-да қолдау көрсетіледі.js және TypeScript.
Өнімділікті арттырудан басқа, GPU қолдануды ұсынамын.js бірнеше себептерге байланысты:
GPU.js JavaScript синтаксисін қолдануға мүмкіндік беретін негіз ретінде JavaScript қолданады;
Ол JavaScript-ті шейдер тіліне автоматты түрде аудару үшін жауапкершілікті өз мойнына алады және оларды құрастырады;
Егер құрылғыда GPU болмаса, ол әдеттегі JavaScript қозғалтқышына оралуы мүмкін. Сондықтан, GPU пайдалану қолайсыздықтар.js. жоқ;
GPU.JS-ті параллель есептеу үшін де қолдануға болады. Сонымен қатар, сіз бір уақытта CPU-да да, GPU-де де бірнеше асинхронды есептеулер жүргізе аласыз.
Осының бәрін ескере отырып, GPU-ны пайдаланбауға ешқандай себеп жоқ.js. Сонымен, мұны қалай бастауға болатынын көрейік.
***
GPU қалай орнатуға болады.js?
GPU орнату.js кез-келген басқа JavaScript кітапханасын орнатуға ұқсас.
Node Үшін.жобаның js:
npm install gpu.js --save
--- немесе ---
yarn add gpu.js
const { GPU } = require('gpu.js')
--- немесе ---
import { GPU } from 'gpu.js'
const gpu = new GPU()
Браузер үшін:
GPU жүктеп алыңыз.js жергілікті немесе CDN қолданыңыз.
<script src="dist/gpu-browser.min.js"></script>
--- немесе ---
<script src="//unpkg.com/gpu.js@latest/dist/gpu- browser.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/gpu.js@latest/dist/gpu-browser.min.js"></script>
<script>
const gpu = new GPU()
...
</script>
Ескерту. Егер сіз Linux-ті қолдансаңыз, дұрыс файлдардың орнатылғанына көз жеткізуіңіз керек: sudo apt install mesa-common-dev libxi-dev
GPU орнату және импорттау туралы білуіңіз керек барлық нәрсе.js. Енді сіз GPU-ны қолданбада қолдана бастай аласыз.
Сонымен қатар, мен GPU-дің негізгі функциялары мен тұжырымдамаларын түсінуге кеңес беремін.js. Сонымен, бірнеше GPU негіздерінен бастайық.js.
***
Кеңес: bit-пен тәуелсіз компоненттерді жасаңыз және бөлісіңіз
Bit-бұл өздігінен жасалған, өңделген және қолдау көрсетілетін компоненттері бар шынымен модульдік қосымшаларды жасауға мүмкіндік беретін ультра кеңейтілетін құрал.
Оны модульдік қосымшалар мен дизайн жүйелерін құру, микро интерфейстерді құру және жеткізу немесе жай ғана қосымшалар арасында компоненттермен бөлісу үшін пайдаланыңыз.
Материалдық UI компоненттері Bit-те жеке қол жетімді.dev
***
Функцияны құру
GPU-де функцияларды анықтауға болады.жалпы JavaScript синтаксисін қолдана отырып, GPU-да іске қосу үшін js.
const exampleKernel = gpu.createKernel(function () {
...
}, settings);
Жоғарыда келтірілген код мысалы GPU функциясының негізгі құрылымын көрсетеді.js. Мен exampleKernel функциясын атадым. Көріп отырғаныңыздай, мен GPU көмегімен есептеулер жүргізетін createKernel әдісін қолдандым.
Шығару мөлшерін де анықтаңыз. Жоғарыдағы мысалда мен Шығыс өлшемін тағайындау үшін settings деп аталатын параметрді қолдандым.
const settings = {
output: [100]
};
Ядро функциясының шығуы бір өлшемді, екі өлшемді немесе үш өлшемді болуы мүмкін, яғни ол 3 ағынға дейін болуы мүмкін. Сіз бұл ағындарға осы команданың көмегімен қол жеткізе аласыз.thread.
1D: [ұзындығы] - мәні [осы.thread.x]
2D: [ені, биіктігі] - мәні [осы.thread.y] [this.thread.x]
3D: [ені, биіктігі, тереңдігі] – value [this.thread.z] [this.thread.y] [this.thread.x]
Соңында, жасалған функцияны, кез-келген басқа JavaScript функциясы сияқты, функция атауын қолдана отырып шақыруға болады: exampleKernel()
***
Ядродағы қолдау көрсетілетін айнымалылар
Сандар
GPU функциясында.js кез-келген бүтін санды немесе өзгермелі нүкте санын қолдана алады.
const exampleKernel = gpu.createKernel(function () {
const number1 = 10;
const number2 = 0.10;
return number1 + number2;
}, settings);
Булевые
GPU-де логикалық мәндер де сақталады.JS, JavaScript сияқты.
const kernel = gpu.createKernel(function () {
const bool = true;
if (bool) {
return 1;
} else {
return 0;
}
},settings);
Массивтер
Сіз kernel функцияларындағы кез-келген мөлшердегі сандық массивтерді анықтап, оларды қайтара аласыз.
const exampleKernel = gpu.createKernel(function () {
const array1 = [0.01, 1, 0.1, 10];
return array1;
}, settings);
Функциялар
Жеке функцияларды ядро функциясы ішінде пайдалану GPU-де де мүмкін.js.
const exampleKernel = gpu.createKernel(function () {
function privateFunction() {
return [0.01, 1, 0.1, 10];
}
return privateFunction();
}, settings);
***
Қолдау көрсетілетін кіріс түрлері
Жоғарыда аталған айнымалы түрлерден басқа, сіз kernel функцияларына бірнеше кіріс түрлерін жібере аласыз.
Сандар
Айнымалы декларацияға ұқсас, сіз бүтін сандарды немесе өзгермелі нүктелерді төменде көрсетілгендей кернель функциясына жібере аласыз.
const exampleKernel = gpu.createKernel(function (x) {
return x;
}, settings);
exampleKernel(25);
Сандардың бір өлшемді, екі өлшемді немесе үш өлшемді массивтері
Сіз array, Float32Array, Int16Array, Int8Array, Uint16Array, uInt8Array массивтерінің түрлерін ядро GPU-ға жібере аласыз.js.
const exampleKernel = gpu.createKernel(function (x) {
return x;
}, settings);
exampleKernel([1, 2, 3]);
Алдын ала тураланған екі өлшемді және үш өлшемді массивтер де ядро функциялары арқылы қабылданады. Бұл тәсіл жүктеуді едәуір жылдамдатады және ол үшін GPU енгізу опциясын пайдалану керек.js.
const { input } = require('gpu.js');
const value = input(flattenedArray, [width, height, depth]);
HTML суреттері
Суреттерді функцияларға беру-бұл GPU-да көруге болатын жаңа нәрсе.js дәстүрлі JavaScript-пен салыстырғанда. GPU көмегімен.js сіз бір немесе бірнеше HTML кескіндерін ядро функциясының массиві ретінде бере аласыз.
// Бір сурет
const kernel = gpu.createKernel(function (image) {
...
})
.setGraphical(true)
.setOutput([100, 100]);
const image = document.createElement('img');
image.src = 'image1.png';
image.onload = () => {
kernel(image);
document.getElementsByTagName('body')[0].appendChild(kernel.canvas);
};
// Бірнеше суреттер
const kernel = gpu.createKernel(function (image) {
const pixel = image[this.thread.z][this.thread.y][this.thread.x];
this.color(pixel[0], pixel[1], pixel[2], pixel[3]);
})
.setGraphical(true)
.setOutput([100, 100]);
const image1 = document.createElement('img');
image1.src = 'image1.png';
image1.onload = onload;
....
// Қосымша суреттер қосыңыз
....
const totalImages = 3;
let loadedImages = 0;
function onload () {
loadedImages++;
if (loadedImages === totalImages) {
kernel([image1, image2, image3]);
document.getElementsByTagName('body')[0].appendChild(kernel.canvas);
}
};
Жоғарыда келтірілген конфигурациялардан басқа, GPU-мен тәжірибе жасау үшін көптеген қызықты нәрселер бар.js. Сіз оларды құжаттамадан таба аласыз. Енді сіз бірнеше конфигурацияларды түсінгендіктен, GPU көмегімен функцияны жазайық.js және оның жұмысын салыстырыңыз.
***
GPU көмегімен бірінші функция.js
Біз бұрын талқылағанның бәрін біріктіре отырып, мен екі массивті 1000 элементке көбейту арқылы GPU және CPU есептеулерінің өнімділігін салыстыруға арналған Кішкентай Angular қосымшасын жаздым.
1-қадам-1000 элементтен тұратын сандық массивтерді құру функциясы
Мен әр элемент үшін 1000 саны бар 2D массивін жасап, оларды келесі қадамдарда есептеу үшін қолданамын.
generateMatrices() {
this.matrices = [[], []];
for (let y = 0; y < this.matrixSize; y++) {
this.matrices[0].push([])
this.matrices[1].push([])
for (let x = 0; x < this.matrixSize; x++) {
const value1 = parseInt((Math.random() * 10).toString())
const value2 = parseInt((Math.random() * 10).toString())
this.matrices[0][y].push(value1)
this.matrices[1][y].push(value2)
}
}
}
2-қадам-ядро функциясы
Бұл қолданбадағы ең маңызды функция, өйткені барлық GPU есептеулері оның ішінде жүреді. Мұнда multiplyMatrix функциясы кіріс ретінде екі сандық массив пен матрица өлшемін алады. Содан кейін ол екі массивті көбейтеді және Performance API көмегімен уақытты өлшеу арқылы жалпы соманы қайтарады.
gpuMultiplyMatrix() {
const gpu = new GPU();
const multiplyMatrix = gpu.createKernel(function (a: number[][], b: number[][], matrixSize: number) {
let sum = 0;
for (let i = 0; i < matrixSize; i++) {
sum += a[this.thread.y][i] * b[i][this.thread.x];
}
return sum;
}).setOutput([this.matrixSize, this.matrixSize])
const startTime = performance.now();
const resultMatrix = multiplyMatrix(this.matrices[0], this.matrices[1], this.matrixSize);
const endTime = performance.now();
this.gpuTime = (endTime - startTime) + " ms";
console.log("GPU TIME : "+ this.gpuTime);
this.gpuProduct = resultMatrix as number[][];
}
3-қадам-процессорды көбейту функциясы.
Бұл бірдей массивтер үшін есептеу уақытын өлшеу үшін қолданылатын дәстүрлі TypeScript функциясы.
cpuMutiplyMatrix() {
const startTime = performance.now();
const a = this.matrices[0];
const b = this.matrices[1];
Как разработчики, мы всегда ищем возможности улучшить произвоительность приложения. Когда дело доходит до web-приложении, мы, в основном, вносим улучшения в коде.
Но задумывались ли вы когда-нибудь скомбинировать мощь графического процессора в своих web-приложениях для повышения производительности?
Эта статья познакомит вас с библиотекой ускорения JavaScript под названием GPU.js и покажет, как улучшить сложные вычисления.
***
Что такое GPU.js и зачем нам его использовать?
Источник: https://gpu.rocks/#/
В кратце, GPU.js – это библиотека ускорения JavaScript, которую можно использовать для вычислений общего назначения на графических процессорах с использованием JavaScript. Он поддерживается в браузерах, Node.js и TypeScript.
Помимо повышения производительности, я рекомендую использовать GPU.js по нескольким причинам:
- GPU.js использует JavaScript в качестве основы, что позволяет использовать синтаксис JavaScript;
- Он берет на себя ответственность за автоматическую трансляцию JavaScript в язык шейдеров и компилирует их;
- Он может вернуться к обычному движку JavaScript, если в устройстве нет графического процессора. Так что, неудобств в использовании GPU.js. не будет;
- GPU.js также можно использовать для параллельных вычислений. Кроме того, вы можете выполнять несколько вычислений асинхронно как в CPU, так и в GPU одновременно.
Учитывая все это, не вижу причин не использовать GPU.js. Так что, давайте посмотрим, как мы можем начать с этим.
***
Как установить GPU.js?
Установка GPU.js аналогична установке любой другой библиотеки JavaScript.
Для Node.js проекта:
npm install gpu.js --save --- или --- yarn add gpu.js
const { GPU } = require('gpu.js')
--- или ---
import { GPU } from 'gpu.js' const gpu = new GPU()
Для браузера:
Скачайте GPU.js локально или используйте CDN.
<script src="dist/gpu-browser.min.js"></script> --- или --- <script src="//unpkg.com/gpu.js@latest/dist/gpu- browser.min.js"></script> <script src="//cdn.jsdelivr.net/npm/gpu.js@latest/dist/gpu-browser.min.js"></script> <script> const gpu = new GPU() ... </script>
Примечание. Если вы используете Linux, вам необходимо убедиться, что у вас установлены правильные файлы, выполнив:
sudo apt install mesa-common-dev libxi-dev
Вот всё что вам нужно знать об установке и импорте GPU.js. Теперь вы можете начать использовать GPU в своем приложении.
Кроме того, я настоятельно рекомендую разобраться в основных функциях и концепциях GPU.js. Итак, давайте начнем с нескольких основ GPU.js.
***
Совет: создавайте и делитесь независимыми компонентами с Bit
Bit – это ультра-расширяемый инструмент, который позволяет создавать по-настоящему модульные приложения с независимо созданными, версионированными и поддерживаемыми компонентами.
Используйте его для создания модульных приложений и дизайн-системах, создания и доставки микро-интерфейсов или просто обмена компонентами между приложениями.
Компоненты Material UI доступны индивидуально на Bit.dev
***
Создание функции
Вы можете определить функции в GPU.js для запуска в GPU, используя общий синтаксис JavaScript.
const exampleKernel = gpu.createKernel(function () { ... }, settings);
В приведенном выше примере кода показана базовая структура функции GPU.js. Я назвал функцию exampleKernel
. Как видно, я использовал метод createKernel
, которая выполняет вычисления с использованием графического процессора.
Также обязательно определите размер вывода. В приведенном выше примере я использовал параметр, называемый settings
, для назначения размера вывода.
const settings = { output: [100] };
Выходные данные функции ядра могут быть одномерные, двухмерные или трёхмерные, что означает, что у нее может быть до 3 потоков. Вы можете получить доступ к этим потокам в ядре с помощью команды this.thread
.
- 1D: [длина] –
value[this.thread.x]
- 2D: [ширина, высота] –
value[this.thread.y] [this.thread.x]
- 3D: [ширина, высота, глубина] –
value[this.thread.z] [this.thread.y] [this.thread.x]
Наконец, созданная функция может быть вызвана, как и любая другая функция JavaScript, с использованием имени функции: exampleKernel()
***
Поддерживаемые переменные в Kernel
Числа
В функции GPU.js можно использовать любое целое число или число с плавающей запятой.const exampleKernel = gpu.createKernel(function () { const number1 = 10; const number2 = 0.10;
return number1 + number2; }, settings);
Булевые
Булевые значения также поддерживаются в GPU.js, как и в JavaScript.const kernel = gpu.createKernel(function () { const bool = true;
if (bool) { return 1; } else { return 0; } },settings);
Массивы
Вы можете определять числовые массивы любого размера в функциях kernel и возвращать их.const exampleKernel = gpu.createKernel(function () { const array1 = [0.01, 1, 0.1, 10]; return array1; }, settings);
Функции
Использование приватных функций внутри функции kernel также возможно в GPU.js.const exampleKernel = gpu.createKernel(function () { function privateFunction() { return [0.01, 1, 0.1, 10]; }
return privateFunction(); }, settings);
***
Поддерживаемые типы входных данных
В дополнение к указанным выше типам переменных, вы можете передавать функциям kernel несколько типов входных данных.
Числа
Подобно объявлению переменной, вы можете передавать целые числа или числа с плавающей запятой в функции kernel, как показано ниже.
const exampleKernel = gpu.createKernel(function (x) { return x; }, settings);
exampleKernel(25);
Одномерные, двухмерные или трёхмерные массивы чисел
Вы можете передавать типы массивов Array, Float32Array, Int16Array, Int8Array, Uint16Array, uInt8Array в kernel GPU.js.
const exampleKernel = gpu.createKernel(function (x) { return x; }, settings); exampleKernel([1, 2, 3]);
Предварительно выровненные двухмерные и трёхмерные массивы также принимаются функциями ядра. Такой подход значительно ускоряет загрузку, и для этого вам нужно использовать параметр ввода из GPU.js.
const { input } = require('gpu.js'); const value = input(flattenedArray, [width, height, depth]);
HTML Изображения
Передача изображений в функции – это новая вещь, которую мы можем увидеть в GPU.js по сравнению с традиционным JavaScript. С помощью GPU.js вы можете передать одно или несколько изображений HTML в виде массива функции kernel.
// Одно изображение const kernel = gpu.createKernel(function (image) { ... }) .setGraphical(true) .setOutput([100, 100]); const image = document.createElement('img'); image.src = 'image1.png'; image.onload = () => { kernel(image); document.getElementsByTagName('body')[0].appendChild(kernel.canvas); }; // Несколько изображении const kernel = gpu.createKernel(function (image) { const pixel = image[this.thread.z][this.thread.y][this.thread.x]; this.color(pixel[0], pixel[1], pixel[2], pixel[3]); }) .setGraphical(true) .setOutput([100, 100]); const image1 = document.createElement('img'); image1.src = 'image1.png'; image1.onload = onload; .... // Добавить ещё изображения .... const totalImages = 3; let loadedImages = 0; function onload () { loadedImages++; if (loadedImages === totalImages) { kernel([image1, image2, image3]); document.getElementsByTagName('body')[0].appendChild(kernel.canvas); } };
Помимо вышеперечисленных конфигураций, есть много интересных вещей для экспериментов с GPU.js. Вы можете найти их в их документации. Поскольку теперь вы понимаете несколько конфигураций, давайте напишем функцию с помощью GPU.js и сравним ее производительность.
***
Первая функция с использованием GPU.js
Объединив все, что мы обсуждали ранее, я написал небольшое Angular приложение для сравнения производительности вычислений GPU и CPU путем умножения двух массивов на 1000 элементов.
Шаг 1 - Функция для создания числовых массивов из 1000 элементов
Я сгенерирую 2D-массив с 1000 числами для каждого элемента и использую их для вычислений на следующих шагах.
generateMatrices() { this.matrices = [[], []]; for (let y = 0; y < this.matrixSize; y++) { this.matrices[0].push([]) this.matrices[1].push([]) for (let x = 0; x < this.matrixSize; x++) { const value1 = parseInt((Math.random() * 10).toString()) const value2 = parseInt((Math.random() * 10).toString()) this.matrices[0][y].push(value1) this.matrices[1][y].push(value2) } } }
Шаг 2 – функция ядра
Это самая важная функция в этом приложении, поскольку все вычисления графического процессора происходят внутри него. Здесь функция multiplyMatrix
получит в качестве входных данных два числовых массива и размер матрицы. Затем он умножит два массива и вернет общую сумму измеряя время с помощью Performance API.
gpuMultiplyMatrix() { const gpu = new GPU(); const multiplyMatrix = gpu.createKernel(function (a: number[][], b: number[][], matrixSize: number) { let sum = 0; for (let i = 0; i < matrixSize; i++) { sum += a[this.thread.y][i] * b[i][this.thread.x]; } return sum; }).setOutput([this.matrixSize, this.matrixSize]) const startTime = performance.now(); const resultMatrix = multiplyMatrix(this.matrices[0], this.matrices[1], this.matrixSize); const endTime = performance.now(); this.gpuTime = (endTime - startTime) + " ms"; console.log("GPU TIME : "+ this.gpuTime); this.gpuProduct = resultMatrix as number[][]; }
Шаг 3 – функция умножения ЦП.
Это традиционная функция TypeScript, используемая для измерения времени вычислений для одних и тех же массивов.
cpuMutiplyMatrix() { const startTime = performance.now(); const a = this.matrices[0]; const b = this.matrices[1]; let productRow = Array.apply(null, new Array(this.matrixSize)).map(Number.prototype.valueOf, 0); let product = new Array(this.matrixSize); for (let p = 0; p < this.matrixSize; p++) { product[p] = productRow.slice(); } for (let i = 0; i < this.matrixSize; i++) { for (let j = 0; j < this.matrixSize; j++) { for (let k = 0; k < this.matrixSize; k++) { product[i][j] += a[i][k] * b[k][j]; } } }
const endTime = performance.now(); this.cpuTime = (endTime — startTime) + “ ms”; console.log(“CPU TIME : “+ this.cpuTime); this.cpuProduct = product; }
Вы можете найти полный демо-проект на моём GitHub аккаунте.
CPU vs GPU – Сравнение производительности
А теперь пора посмотреть, верна ли вся эта шумиха вокруг GPU.js и вычислений на GPU. Поскольку в предыдущем разделе я создал приложение Angular, я использовал его для измерения производительности.
Как вы можете увидеть, программа на GPU потребовало всего 799 мс для вычислений, в то время как на CPU заняло 7511 мс, что почти в 10 раз больше.
Не останавливаясь на этом, я провел те же тесты в течение пары циклов, изменяя размер массива.
Во-первых, я попробовал использовать массивы меньшего размера и заметил, что CPU занимает меньше времени, чем графический процессор. Например, когда я уменьшил размер массива до 10 элементов, CPU потребовалось всего 0,14 мс, а GPU - 108 мс.
Но по мере увеличения размера массива наблюдался явный разрыв между временем, затрачиваемым на GPU и CPU. Как вы можете видеть на графике выше, GPU оказался победителем.
***
Вывод
Основываясь на моем эксперименте с использованием GPU.js, он может повысить производительность приложений JavaScript.
Но мы должны помнить об использовании GPU только для сложных задач. В противном случае мы будем тратить ресурсы впустую и, в конечном итоге, снизим производительность приложения, как показано на приведенном выше графике.
Однако, если вы еще не пробовали GPU.js, я приглашаю вас всех попробовать его и поделиться своим опытом.
Спасибо, что прочитали!!!
***
От переводчика
Статься переведена с английского на Medium: Оригинальная статья
Это мой первый пост на этой площадке, так что буду рад вашим советам!