プログラミングの話をしていると「同期」「非同期」という難しい言葉が出てきて、何のこっちゃかわからないですよね。でも実は、これらは僕たちの日常生活でもよくある経験。この記事を読めば、非同期処理がどういうものか、そしてなぜプログラムで必要なのかが「あーそういうことか」とスッと理解できるようになりますよ。
- 非同期処理とは、複数の作業を同時並行で進める方法で、つまり待つ時間を減らすやり方のこと
- インターネットからデータを取ってくるとき、その完了を待たずに他の処理を進められるのがメリット
- スマホやWebサイトが快適に動く理由は、非同期処理のおかげで、ユーザーは待たされずに使えるストレスフリーな環境が作られているから
もうちょっと詳しく
プログラムが命令を実行するとき、通常は上から順番に、一つずつこなしていきます。これを同期処理と呼びます。でも、ネットワークからデータをもらうとか、ファイルを読み込むとか、時間がかかる処理があると、その完了を待つ間、他の処理はストップしてしまいます。これは非常に効率が悪い。だから、時間がかかる処理を「裏で実行させておいて」「完了したら教えてね」という仕組みが非同期処理です。ユーザーの立場からすると、アプリがくずおれたり固まったりせず、スイスイ動いているように見えるわけです。
非同期=「待たずに先に進む」という考え方
⚠️ よくある勘違い
→ 実際には、処理を順番に切り替えながら進めているだけ。コンピュータは本当には「同時」にはやっていません。ただ、すごく早く切り替えるから「同時っぽく見える」だけです。
→ 待ってる間に別の作業をどんどん進める。だからユーザー体験が良くなる。これが正しい理解です。
[toc]
非同期処理とは、結局何なのか
「同時にやる」という考え方
非同期処理を理解するためには、まず「同期処理」とは何かを知る必要があります。同期処理というのは、プログラムが命令を一つ実行して、それが完了するのを待ってから、次の命令を実行するというやり方です。学校の授業をイメージしてください。先生が問題を出す。みんなが答える。その答え合わせが完全に終わってから、次の問題に進む。こんな感じです。これなら順序が明確で、わかりやすいですよね。
でも、現実の学校ではどうでしょう。宿題を出すとき「来週までに終わらせといてね」と言いますよね。生徒たちが宿題をやっている間、先生は別のクラスを教えたり、テストの採点をしたりしている。つまり、宿題が完了するのを待たずに、別の仕事を進めているわけです。これが非同期の考え方です。プログラムの世界も同じ。時間がかかる処理は裏で走らせておいて、その完了を待たずに、次々と別の処理を進める。これが非同期処理です。
具体例:スマホアプリで分かる非同期
あなたがスマホでInstagramを見ているとします。写真を見ていて「いいね」をタップしたら、その情報がサーバーに送られて、データベースに保存される必要があります。でもこの処理は時間がかかる。データはアメリカのサーバーに送られて、保存されて、また結果が返ってくる。これには0.1秒以上かかるかもしれません。
もし同期処理だったら、どうなるでしょう。「いいね」をタップ→ボタンが固まる→0.1秒以上待つ→ようやく反応する。この間、スマホは完全に固まっていて、スワイプもできないし、コメントも書けない。これは超イライラしますよね。
でも実際のInstagramは違う。「いいね」をタップ→ボタンがすぐに反応→ハートマークが表示される→その間に、裏では通信が進んでいる。ユーザーは固まらず、次の写真をスワイプできる。これが非同期処理の力なんです。処理を「後で完了させる」ことで、ユーザーの操作をブロックしない。これがスマートな設計なんですよ。
なぜ非同期処理が必要なのか
待ち時間を活用する効率性
非同期処理が必要な理由は、シンプルに言うと「待ち時間をもったいないから」です。想像してみてください。あなたが図書館から本を借りるとき、借りるのに時間がかかるから、その間に読むべき本を選んでいますよね。図書館員が本を探している間、あなたは何もせずに突っ立ってるわけじゃない。別の本を見てる。これが効率的な使い方です。
プログラムも同じ。データベースからデータを取ってくるのに1秒かかるなら、その1秒の間に他の計算を進めちゃおう、というわけです。特にWebサイトやアプリは、ネットワーク経由でデータをやり取りするから、待ち時間がすごく長い。だからこそ、非同期処理が必須なんです。
ユーザー体験の向上
スマホやパソコンで快適にアプリが動いているのは、非同期処理のおかげです。もし全部同期処理だったら、毎回「処理中…」という表示が出て、その間何もできない状態が続くわけです。
例えば、YouTubeで動画を見ながら別のタブでTwitterをチェックするとします。同期処理だったら、動画のダウンロードが完了するまで、他のタブは動きません。つまり、ブラウザ全体が固まる。こんなのはストレスです。でも実際は、動画がバックグラウンドで勝手にダウンロードされていて、その間にTwitterのタイムラインをスクロールできる。これが非同期の力です。
同期処理との違いを図で理解する
同期処理のイメージ
同期処理は「順番に待つ」という考え方です。具体的には以下のような流れになります:
- ステップ1を実行
- ステップ1の完了を待つ
- ステップ2を実行
- ステップ2の完了を待つ
- ステップ3を実行
ちょうど、レジで順番待ちするみたいなものです。一人のお客さんの会計が終わるまで、次のお客さんは何もできない。こういう仕組みが同期処理です。
非同期処理のイメージ
非同期処理は「並行して進める」という考え方です:
- ステップ1を開始(完了を待たず)
- ステップ2を開始(完了を待たず)
- ステップ3を開始(完了を待たず)
- 各ステップが勝手に完了していく
- 完了したものから順に結果を処理
これは、ファーストフード店でオーダーするようなもの。オーダーを提出すると「番号札をどうぞ」と言われて、その間に席に座ったり、飲み物をもらったり、友達とおしゃべりしたりできる。完成したら番号で呼ばれる。このシステムが非同期処理です。
どっちが速い?
同期処理は「安全で分かりやすい」ですが「遅い」。非同期処理は「複雑だけど速い」。実際に時間を比較してみましょう。
同期処理で3つのタスク(各1秒かかる)をやったら、合計3秒かかります。1秒→完了→2秒→完了→3秒→完了です。
でも非同期処理なら、3つのタスクを同時に開始できます。だから1秒で全部完了します。3倍速いわけです。これが非同期処理の最大のメリット。時間がかかる処理が多いほど、効果は大きいんですよ。
実際のプログラムで見る非同期処理
JavaScriptの非同期処理(fetch API)
具体的なプログラムの例を見てみましょう。JavaScriptというプログラミング言語は、Webサイトを動かすために使われます。Webサイトがサーバーからデータをもらうとき、こういうコードを書きます:
- 「サーバーからこのURLのデータをもってこい」と命令する
- その命令を実行した直後「完了を待たずに、次に進め」という指示も一緒に出す
- データがサーバーから帰ってきたら「じゃあここからこうしてね」という処理を実行する
つまり、命令を出して、完了を待たずに次へ進む。これが非同期処理です。もし待ってたら、ユーザーはブラウザが固まったと思うでしょう。でも実際は、データが返ってくるのを待ってる間に、ページをスクロールしたり、ボタンをクリックしたりできる。
スマホアプリでの非同期処理
スマホアプリも同じです。例えば、LINEでメッセージを送るとき、送信ボタンを押したらすぐに「送信済み」マークが出ますよね。でも実際には、そのメッセージがサーバーに送られて、相手のスマホに届いて、といった処理が実行されています。これらはすべて非同期で動いている。だから、メッセージを送った直後に別の人とチャットできるわけです。
もし同期処理だったら、送信ボタンを押してから、メッセージが完全に相手に届くまで、アプリは何もできなくなる。画面が固まったように見えます。これは最悪のユーザー体験です。だからスマホアプリは必ず非同期処理を使っているわけなんですよ。
Webサイトの読み込み
Webサイトを開いたとき、画像がだんだん読み込まれていくのを見たことありますか?これも非同期です。
実は、Webサイトを見るときは、いろんなファイルが必要です。HTMLというテキスト、CSSというデザイン、JavaScriptというプログラム、JPGやPNGという画像。これらが全部揃わないと、サイトは表示されません。
もし同期処理だったら、全てのファイルが揃うまで、ユーザーは真っ白な画面を見てることになる。すごく遅く見えますよね。でも実際は、HTMLが最初に読み込まれて、画面に表示されます。その間に、画像やJavaScriptは別で読み込まれている。このおかげで、ユーザーは早くコンテンツを見られるわけです。
非同期処理をマスターするコツ
「完了をどう判定するか」という考え方
非同期処理で大事なのは「完了をどう判定するか」です。データを取ってくる命令を出したら、「完了したら教えてね」という仕組みが必要です。プログラミングでは「コールバック関数」や「Promise」という仕組みで、「完了したらこれをやって」という指示を出します。
例えるなら、レストランで食事をするときの流れ:
- オーダーを出す(「パスタをください」と言う)
- 番号札をもらう(「31番です」)
- 席に座ってメニューを眺めたり、飲み物を飲んだりしている
- 「31番」と呼ばれたら、パスタを取りに行く(これが「完了」の通知)
プログラムも同じ。「データを取ってくる」という命令を出して、番号札(ID)をもらう。その間に他の処理をする。データが揃ったら、その番号で呼ばれて、結果を処理する。こういう流れなんです。
エラーが発生した時はどうする?
非同期処理で大事なのが「もし失敗したらどうするか」という準備です。ネットワークが遅かったり、サーバーが壊れてたり、いろんなことが起こります。そういう時は「エラーが起きました」という別の処理を実行します。
具体例をあげると、YouTubeで動画を開いたけど、ネットが悪くて読み込めないことがありますね。そうしたら「エラー:動画を読み込めません」というメッセージが出る。これは非同期処理で「失敗のパターン」を準備しているからです。
デバッグ(バグ探し)が難しい理由
非同期処理の難しい点は「何が起こっているのか、追いにくい」ということです。同期処理なら「1→2→3」と順番に進むから、どこで失敗したかが明確です。でも非同期処理は「1を開始→2を開始→1が完了→3を開始→2が完了」みたいに、順番がバラバラになる。だからバグが起きたとき「どこが悪いのか」を探すのが難しいわけです。
だから、プログラマーは非同期処理を使うときに「ここが完了したら、こうする」「ここが失敗したら、こうする」という流れを、しっかり設計してから書き始めるんですよ。ちょうど、料理の手順を全部書き出してから調理するようなものです。
