質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.12%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

OS

OS(オペレーティングシステム)は、システムソフトウェアの一種であり、一般的に、ハードウェアを直接的に管理・操作する最も中心的な機能を有するソフトウェアがオペレーティングシステムとして呼ばれます。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Lua

Luaは、汎用のスクリプト言語の一つで、 移植性が高く、高速な実行速度などの特徴を持ち 手続き型・オブジェクト指向言語としても利用可能で 関数型言語、データ駆動型の要素も併せ持っている言語です。

解決済

c10k問題:第二次プリエンプティブ戦争

mit0223
mit0223

総合スコア3369

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

OS

OS(オペレーティングシステム)は、システムソフトウェアの一種であり、一般的に、ハードウェアを直接的に管理・操作する最も中心的な機能を有するソフトウェアがオペレーティングシステムとして呼ばれます。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Lua

Luaは、汎用のスクリプト言語の一つで、 移植性が高く、高速な実行速度などの特徴を持ち 手続き型・オブジェクト指向言語としても利用可能で 関数型言語、データ駆動型の要素も併せ持っている言語です。

2回答

5リアクション

3クリップ

3898閲覧

投稿2016/10/29 02:20

編集2016/10/31 23:58

また、具体的な課題が含まれていないご意見募集型の質問で失礼します。

####昔話
Windows 3.1 や Mac OS System 4 など昔のパソコンのOSはノンプリエンプティブ・マルチタスク(以降、協調的マルチタスクと呼びます)でした。
これらのOSではアプリケーションが自発的にCPUを開放しないとタスクが切り替わらず、一つでもCPU の開放のしかたが悪いプログラムがあると、OSごと凍りついてしまうものでした。そのことが不評で、今や全面的にプリエンプティブ・マルチタスクのOSに置き換えられました。

####帰ってきた協調的マルチタスク
今、マルチスレッドのアーキテクチャが抱えるC10K問題に対応するために node.js、 nginx+lua などイベント駆動型やコルーチン型(=協調的マルチタスク)で処理する処理系が出始めました。そして、従来の一つのリクエストを一つのスレッドが処理するプリエンプティブなマルチスレッド処理系に比べて高い性能が出るということが定説になっています。

####また戦いが
その状況の中で、最近のWebでの議論を見ていると、Linux のマルチスレッドが非常に軽量・高速で協調的マルチタスクじゃなくてもマルチスレッドで十分性能が出るというベンチマーク結果が出てきているようです(※1)。そうなると、協調的マルチタスクの処理系はまたなくなってしまうのでしょうか。
前述の昔話において、パソコンのOSがプリエンプティブマルチタスクに置き換えられるときも、OSの実装者は「プリエンプティブマルチタスクなんて必要ない。プログラマが時間のかかる処理を実装するときに処理の途中経過を報告したり、中断したりする機能をちゃんと入れてれば、協調的マルチタスクのほうが効率が高いに決まっている」と執拗に粘ったのですが、世の中の流行には逆らえず(というよりも質の悪いプログラムの多さに負けて)、負けてしまいました。
今回もプリエンプティブマルチタスク(マルチスレッド派)対協調的マルチタスク(イベント駆動型やコルーチン派)の戦いが始まっているように思います。これを第二次プリエンプティブ戦争と呼びましょう。

####協調的マルチタスク派
(いくつか回答いただいて、自分の好みの問題とC10K問題が直結していないことに気が付き、書き直しました)
私は個人的にはシングルスレッドイベント駆動型でコーディングするのが好きで、c10K問題を理由にマルチスレッドプログラミングのパラダイムを駆逐して欲しいくらいに思っています。たとえば、DBへの問い合わせが長い時間かかる場合に、ユーザからの要求やシステムのシャットダウンに対応して問い合わせを中断できるようにする場合、マルチスレッドで割り込みを気にしながら順次的に書くよりも自分で状態遷移を管理するほうが簡単ではないでしょうか。マルチスレッドの場合、
(DBへの問い合わせを中止できるようなドライバがあるかどうかはおいておいて)

javascript

class 問い合わせ { do() { try { DBへの問い合わせ } catch (CancelSignal cs) { if (微妙なタイミング判定) { 問い合わせ中止処理 } } } onCancel() { 問い合わせ実行中スレッドへ CancelSignal を送信 } }

となり、問い合わせの終了とキャンセルシグナルの入力との微妙なタイミング判定(排他制御)が必要ですが、シングルスレッドであれば、

javascript

class 問い合わせ { do() { DBへの問い合わせ((event) => this.handler(event)); } handler (event) { ... } onCancel() { 問い合わせ中止処理 } }

と書けて、シングルスレッドなので、handler 呼び出しと onCancel の呼び出しは早い者勝ちとなるわけです。

そもそも、OSレベルでは多重入力はイベント駆動で実装されているわけで、そのイベント駆動をそのままコーディングできるシングルスレッドイベント駆動プログラミングって気持ち良くないですか?

####質問:シングルスレッドプログラミングは好きですか?残ると思いますか?
いくつか回答いただいて、シングルスレッドプログラミングとC10K問題が直結していないことに気が付きましたが、質問としてはC10K問題で復権したシングルスレッドプログラミングをどう思うかというポイントに変更して続けさせていただきたいと思います。
JavaScript のコールバックは嫌いですか? lua などコルーチンの yield って懐かしくないですか?マルチスレッドプログラミングって難しくないですか?

####補足1:マルチコアについて
それほど性能がCPUに依存するアプリが少ないのではないかとは思いますが、、CPU依存が強い場合でもワーカプロセスに負荷分散することで、プログラム自身はシングルスレッド・協調的マルチタスクで書くことが可能だと思います。特に並列演算で問題が解決するような場合は、ワーカプロセス側で GPUをつかったり、SIMD命令を使うなど、マルチコア以上に並列度をあげる工夫が必要ではないかと考えます。この場合は、マルチスレッドプログラミングというよりも並列処理プログラミングになってくると思います。となると、やはりマルチスレッドプログラミングは不要なのではないかと思えてきます。

####補足2:イベント駆動型プログラミングの順次的記述
回答でイベント駆動型プログラミングのデメリットとしてサブルーチンのネスト構造などモジュール化がやりにくいという指摘がありました。 Javascript では、サブルーチンの呼び出し後の継続処理をコールバック関数(というかクロージャ)に記述するという技法で回避し、非同期でありながらモジュール化を行うことに成功しています。しかし、この技法はコールバック地獄と呼ばれており、モジュール化には成功しましたが、順次処理を記述すると、ネストがどんどん深くなるという欠点がありました。次世代 Javascript である es6 では、この問題を Promise という技法でさらに回避しております。
ここで、普通に順次的に記述したプログラムと Promiseを使って非同期処理可能でありながら順次的に記述したプログラムを比較してみます。

普通の順次的記述

Javascript

function main() { let x = 'default value of x'; let y = 'default value of y'; let z; try { z = getValuesForZ(x); z = z.map(item => processItem(item)); if (z.includes(processItem(x))) { y = processY(y); } console.log("x = " + x + ", y= " + y + ", z= " + z); } catch (e) { console.log(e); } } function getValuesForZ(arg) { return ['value1', 'value2'].concat(arg); } function processItem(item) { return 'processed:' + item; } function processY(y) { return processYnest(y); } function processYnest(y) { return 'processed in nested function:' + y; } main()

Promise を使った非同期処理可能な順次的記述

Javascript

function main() { Promise.resolve({ x: 'default value of x', y: 'default value of y' }) .then(getValuesForZ()) .then(state => { return Promise.all(state.z.map(item => Promise.resolve(item).then(processItem()))) .then(z => Object.assign(state, {z})); }) .then(state => { return Promise.resolve(state.x).then(processItem()).then(r => { if (state.z.includes(r)) { return Promise.resolve(state).then(processY()); } return state; }); }) .then(state => { console.log("x = " + state.x + ", y= " + state.y + ", z= " + state.z); }) .catch(e => { console.log(e); }); } function getValuesForZ() { return state => Object.assign(state, {z:['value1', 'value2'].concat(state.x)}); } function processItem() { return item => 'processed:' + item; } function processY() { return state => { return Promise.resolve(state.y) .then(processYnest()) .then(y => Object.assign(state,{y})); }; } function processYnest() { return y => 'processed in nested function:' + y; } main()

普通版は 34行に対して、Promise 版は48行と行数は増えてしまいましたが、処理順にプログラムを書くことができて、かつ、サブルーチンによるモジュール化もできていると思います。
モジュール化のみそは、サブルーチンが演算結果を返すのではなく、演算を行う関数を返すことです。このようにすることで、呼び出し側は非同期にその関数を呼び出すことができるわけです。
プログラムの詳細な説明は避けますが、順次処理、条件判定、繰り返し処理、サブルーチンのネスト呼び出しを含める例となっています。プログラムの処理内容には何の意味もありません。また、両方を比較しやすいように非同期処理は入っていませんが、Promise版の方ではいくらでも非同期処理を挿入できますが、普通版では非同期処理を挿入することは不可能です。

※1の参考:
TCP/IP - Solving the C10K with the thread per client approach
「サーバ書くなら epoll 使うべき」は、今でも正しいのか
いずれも、協調的マルチタスクに比べれば性能は出ないと思いますが、「協調的マルチタスクがないと1万コネクションはできないのかというとそうではない」という主張だと思います。桁が上がって10万コネクションになれば、やはり協調的マルチタスクが必要なのかもしれません。

sharow, i50, LLman, pack, sanai👍を押しています

以下のような質問にはリアクションをつけましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

リアクションが多い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

2016/10/29 06:36依頼された後にこの質問は修正されています

こちらの質問が複数のユーザーから「過去の低評価」という指摘を受けました。

yohhoy

2016/10/29 04:42

「その状況の中で、最近のWebでの議論を見ていると、Linux のマルチスレッドが非常に軽量・高速で協調的マルチタスクじゃなくてもマルチスレッドで十分性能が出るというベンチマーク結果が出てきているようです。」は具体的な情報ソースありますか?C10Kに耐えうる"OSスレッド"というのは聞いたことがありません...
mit0223

2016/10/29 10:50

yohhoy様、一応ソースを追加しましたが、補足のとおり、OSスレッドで協調的マルチタスクと同等に性能が出るという話ではありませんでした。誤解を招く表現ですみませんでした。
yohhoy

2016/10/29 15:38

参考URLありがとうございました。思っていた以上に"動く"ものなのですね(私の知識が古かったようです)。とはいえStackOverflow回答にあるように、OS側のリソース制限値をチューニングする必要はあるようですね。

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

OS

OS(オペレーティングシステム)は、システムソフトウェアの一種であり、一般的に、ハードウェアを直接的に管理・操作する最も中心的な機能を有するソフトウェアがオペレーティングシステムとして呼ばれます。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Lua

Luaは、汎用のスクリプト言語の一つで、 移植性が高く、高速な実行速度などの特徴を持ち 手続き型・オブジェクト指向言語としても利用可能で 関数型言語、データ駆動型の要素も併せ持っている言語です。