Skip to content

Instantly share code, notes, and snippets.

@poppycocker
Last active December 26, 2017 05:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save poppycocker/6d591dfce0da3f9580244bf766bb0d0a to your computer and use it in GitHub Desktop.
Save poppycocker/6d591dfce0da3f9580244bf766bb0d0a to your computer and use it in GitHub Desktop.
Web Workers Demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ww</title>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
</head>
<body>
Count Prime Numbers(of 0 to 200,000) With Web Workers
<ul>
<li>
<button id="run1">run with 1 thread</button>
<p id="result1"></p>
<p id="durations1"></p>
</li>
<li>
<button id="run2">run with 2 threads</button>
<p id="result2"></p>
<p id="durations2"></p>
</li>
<li>
<button id="run4">run with 4 threads</button>
<p id="result4"></p>
<p id="durations4"></p>
</li>
<li>
<button id="run8">run with 8 threads</button>
<p id="result8"></p>
<p id="durations8"></p>
</li>
</ul>
<script src="src.js"></script>
</body>
</html>
// Workerを1つ生成し、その終了イベントを監視するPromiseを生成して返す
const generatePromise = (worker, i, workers) => {
return new Promise((resolve, reject) => {
worker.onmessage = evt => {
resolve(evt.data)
}
worker.onerror = err => {
reject(err)
}
// Worker毎の負荷を平準化する
// (検査対象の数値が大きいほど重いので、前半後半のような分け方は不適当)
// (1ブロック=幅1000を交互に分担する)
// 例)Worker数3の場合:
// 0: 0- 999, 3000-3999, ...
// 1: 1000-1999, 4000-4999, ...
// 2: 2000-2999, 5000-5999, ...
worker.postMessage({
order: i,
limit: 200000,
workers: workers.length,
stride: 1000
})
})
}
// threads分のWorkerを生成して並列処理を実行する
const run = threads => {
const startTime = performance.now();
const workers = []
for (let i = 0; i < threads; i++) {
workers.push(new Worker('worker.js'))
}
// 実行
const promises = workers.map(generatePromise)
Promise.all(promises)
.then(values => {
// サマリー
const duration = ((performance.now() - startTime) / 1000).toFixed(3)
const count = values.reduce((prev, cur) => prev + cur.count, 0)
$(`#result${threads}`).text(`${count} primes are found in ${duration} sec.`)
// Worker毎の結果
const netDurations = values.map((value, i) => `${i}: ${value.duration.toFixed(3)}s`).join(', ')
$(`#durations${threads}`).text(netDurations)
})
.catch(err => {
$(`#result${threads}`).text('an error occured. see console.')
console.error(err)
})
}
// Worker数に応じた実行ボタンを生成、処理実行のハンドラを設定
[1, 2, 4, 8].forEach(threads => {
$(`#run${threads}`).click(() => {
$(`#result${threads}`).text('running...')
run(threads)
})
})
// 並列化の効果を見たいだけなので、あえて効率の悪いアルゴリズムにしている
const judgePrimeByInefficientWay = n => {
if (n < 2) {
return false;
}
if (n === 2) {
return true;
}
for (let i = 2; i < n; i++) {
if (n % i === 0) {
return false;
}
}
return true;
};
// messageを受け取って処理開始
self.addEventListener('message', (msg) => {
const startTime = performance.now()
let count = 0
let i = msg.data.order * msg.data.stride
while(i < msg.data.limit) {
if (judgePrimeByInefficientWay(i)) {
count++
}
i++
if (i % msg.data.stride === 0) {
// 1ブロック分完了、次のブロックへ
i += msg.data.stride * (msg.data.workers - 1)
}
}
const duration = (performance.now() - startTime) / 1000
// 呼び出し元にmessageを返す
self.postMessage({
count,
duration
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment