Managed Service Column <システム運用コラム>

非同期処理

Category: 入門編

2021.01.16

はじめに

非同期処理とは、一つのタスクを実行中であっても他のタスクを実行できる実行方式をいいます。非同期処理をうまく実装することで、ユーザーはアプリケーションの処理待ちを気にすることなくアクセスすることができるため、ユーザビリティを考えるうえで重要な要素になります。

一方で、非同期処理は実装方法などを工夫しないと、結果的に全体像が見えにくくなったり、処理時間が長くなったりすることもあります。

このコラムでは、そもそも同期処理とは何なのかを説明したうえで、非同期処理の概要や重要性などについてご紹介します。

同期処理とは?

非同期処理について詳しく説明する前に、まず同期処理について説明します。
同期処理とは、複数のタスクを実行する際に一つずつ順番にタスクが実行される方式のことです。同期処理の場合、必ずプログラムに記載したとおりの順番でタスクが処理されます。そのため処理全体を把握しやすいメリットがあります。

一方でデメリットは、タスクの処理完了までに時間がかかり、ユーザーにとってはストレスとなる場合があることです。

同期処理
同期処理

「タスク1」「タスク2」を同期処理するアプリケーションがあったとします。このアプリケーションが、ユーザーAからリクエストを受けた場合を例にとって説明します。

プログラムに書かれた通りの順番でタスクが処理されるので、タスク2が終わるまでタスク1の処理が中断され、ユーザーからは画面が固まったように見えてしまいます。

非同期処理とは?

非同期処理とは、あるタスクを実行している最中に、その処理を止めることなく別のタスクを実行できる方式を指します。特にJavaScriptではAjax(Asynchronous JavaScript and XML)という技術を用いた非同期処理が有名です。

非同期処理の場合は、実行の順番を待たないため、処理が完了する順序はその都度異なります。

同期処理
非同期処理

「タスク1」「タスク2」を非同期処理するアプリケーションに、ユーザーAから「タスク1,2」を処理するリクエスト、ユーザーBから「タスク1」のみを処理するリクエストがあった場合で説明します。

非同期処理は、あるタスクを実行している最中にその処理を止めることなく別の処理を実行できるため、上図のように、ユーザーAのリクエストを処理中にユーザーBからのリクエストがあっても、ユーザーBはユーザーAの処理完了を待たずに、結果を受け取ることができます。

非同期処理をうまく活用すると、全体の処理速度を速められるメリットがあります。その反面、現在何の処理を行っているのかなどプログラムの全体像が複雑になりやすいというデメリットがあります。

このとき注意しておきたいのは、非同期処理と並行処理の違いです。並行処理とは文字どおり複数の処理を同時進行で行うことです。一方、非同期処理は処理を止めることなく実行できるというだけです。そのため、非同期処理と並行処理は共存が可能で、並行処理を実現するために非同期処理で実装するということもありえます。

非同期処理はなぜ重要?

プログラムの内容が複雑になりかねないにもかかわらず、非同期処理が重要である理由は、快適な操作性を確保するためです。

非同期処理を実装すると、例えばデータの読み込みなど重い処理やネットワーク通信など一定ではない待ち時間が発生する際にも、他の処理が待たされることがないのでアプリケーションがフリーズすることがありません。

スマートフォンアプリケーションの応答性や操作性を厳しく評価するユーザーの傾向は、デスクトップアプリケーションへも広がっていくと思われます。よりよい応答性、操作性を求めるユーザーの声に応えるためにも、非同期処理はますます重要になっていくでしょう。

プログラムでの非同期処理の実装

非同期処理を行う際には、どのように機能を実装するのかといった方法が課題になります。エンジニアにとっても、非同期処理は決して簡単なプログラムではありません。コードの記述方法を工夫しないと、非常に複雑で全体像が把握しづらくなってしまうため、わかりやすい記述を意識することが大切です。
では具体的に、どのように実装するのか方法を見ていきましょう。

コーディングによる実装

非同期処理を実装するためには、例えばJavaScriptの場合、Callback(コールバック)、Promise、Async/Awaitなどが必要になります。

コールバック

コールバックとは、非同期処理として実行したものが完了した際に実行する別の処理を指します。 例えば、「数字を1から10まで数える」という処理を非同期処理として実装し、「ポップアップで完了と表示する」という処理をcallbackの処理として実装することで、10まで数え終わったら完了というポップアップが出る処理にすることができます。

Promise

Promiseは、非同期処理を抽象化することにより、コーディングをよりわかりやすく見せる処理です。Promiseを活用することで、複数の非同期処理を順番に実行し、前の処理が完了してからその結果を次の処理で使うといったことが簡単に実現できます。これにより、コールバックのネスト※(入れ子)が深くなりすぎること、例外的な処理が困難であること、といった問題がクリアになります。

※コールバックのネストの問題は、「コールバック地獄」と呼ばれるほど、コーディングを複雑化させてしまうことがあります。

別スレッドによる実装

別スレッド(作業の実行単位)による実装は、前述の並行処理などを実現するための仕組みで、マルチスレッドとも呼ばれます。別スレッドによる実装では、実行したい2つ以上の処理を読み込んだタイミングでそれぞれを別のスレッドに分けて実行することで、並行して処理することが可能です。

イベントループによる実装

イベントループは、Node.jsにおけるJavaScriptの実行の際に用いられます。
そもそもイベントループでは、一つのタスクにより他のタスクが待機中になってしまうことを問題視します。つまり、あるタスクの実行中に次の工程のタスクを行う準備が完了しているのかどうかを定期的に監視し、準備が完了していれば処理を行うよう指示するのです。

イベントループによる実装を利用すれば、結果的にタスクの実行によって作業が滞ってしまう事態を避けられます。ただし、イベントループの概念やコーディングは非常に高度なため、使いこなすためには相応のレベルが要求されます。

クラウドにおける非同期メッセージングサービス

非同期処理は、例えば Azureが提供する非同期メッセージングサービスAzureキューでも用いられています。
Azureキューのような非同期メッセージングサービスは、マイクロサービスにて重要な役割を果たします。マイクロサービスというのは、「独立した小さなサービス」をコンポーネントと用意し、それらを複数組み合わせることで1つのアプリケーションとする、システム設計の考え方です。このコンポーネントはサーバレスであることが多く、Azure では Azure functions や AKS がよく使われます。Azure キューは、これらのコンポーネントを繋ぐ役割を果たします。

おわりに

システムの実装には多くの場所で非同期処理が使われています。これまでに述べた通り、プログラムでの実装だけでなく、クラウドのサービスとしての実装もあります。さまざまなサービスサイトを利用する際に、表面的には見えない部分ではありますが、そこで使われている技術としてより詳細を調べてみるのも良いでしょう。

クラウドのサービスとしてのAzureキューについては、Azureコラム「Azure ストレージが提供する4つのサービスを紹介 (Azure キュー)」でも紹介しています。Azure キューのような非同期処理がどのように使われるか、またなぜ非同期処理が重要なのかイメージできるように、最も簡単なマイクロサービスを実際に作ってみました。こちらも合わせてチェックしてください。

Tag: 非同期処理

関連記事

Contactお問い合わせ

お見積もり・ご相談など、お気軽にお問い合わせください。

single.php