Async/await
![]() | この記事には独自研究が含まれているおそれがあります。 |
async/await(エイシンク/アウェイト)とは、非同期プログラミングを簡潔かつ読みやすくするための構文である[1][2][3][4]。これは主に、コールバックやプロミスの複雑さを軽減し、コードの可読性と保守性を向上させる目的で導入された。非同期処理は、入出力処理やネットワーク通信など、時間のかかる処理を他のタスクをブロックせずに実行するための手法であり、async/awaitはこれをより直感的に扱えるようにする。
async/awaitの起源は非同期プログラミングの歴史にあり、Python[1][2]やJavaScript[3][4]など、主要なプログラミング言語で順次採用されてきた。基本的な概念として、非同期関数はasync
キーワードを使って定義され、await
キーワードによって非同期処理の完了を待つことができる。
プログラミング言語毎に実装方法や使用例が異なり、特にPython[1][2]、JavaScript[4][5]、C#[6][7]などで広く利用されている。各言語での実装には若干の違いがあるが、基本的な構文と使い方は共通している。
async/awaitの利点として、コードの可読性向上、デバッグの容易さ、パフォーマンスの向上が挙げられる一方、学習曲線の高さやサポートするランタイムの制限といったデメリットも存在する[1][4]。具体的な使用例としては、Web開発における非同期処理や、データベースアクセスの最適化などが挙げられる。
async/awaitを効果的に活用するためには、適切なエラーハンドリングやリソース管理、パフォーマンスの最適化が必要である[1][4]。非同期処理のデバッグやデッドロックの回避、スレッドの管理といったよくある問題も対策が求められる。
なお、async/await以外の非同期処理手法としては、コールバックやプロミス、リアクティブプログラミングなどがあり、それぞれ異なる特徴と利点をもつ[3][8]。
このページでは、async/awaitの理論的背景から歴史、具体的な使用例、ベストプラクティス、代替手法に至るまで、広範囲に渡る情報について詳述する。
理論的背景
[編集]非同期処理とは
[編集]非同期処理とは、プログラムが特定のタスクを実行している間に他のタスクを同時に進行させる手法のことを指す[4][5][8][9]。これにより、プログラムは時間のかかる処理(例えば、ファイルの読み書きやネットワーク通信)を他のタスクをブロックせずに続行することができる。非同期処理は、システムの応答性を向上させ、ユーザーエクスペリエンスを改善するために重要である。非同期処理を実現するためには、イベントループ、コールバック、プロミスなどのメカニズムが用いられる。これらはプログラムが特定のイベントの発生を待機し、そのイベントが発生したときに対応する処理を実行することを可能にする。
コールバックとプロミスの限界
[編集]非同期処理を実現するための初期の手法として、コールバックが広く用いられてきた[3][4][5][10]。コールバックは、関数が実行完了した後に実行される別の関数を渡す方法である。しかし、コールバックはその簡潔さにもかかわらず、複雑な非同期処理を管理する際に「コールバック地獄」と呼ばれる問題を引き起こす。コールバック地獄では、ネストが深くなり、コードの可読性と保守性が著しく低下する。
この問題を解決するために、プロミスという概念が導入された[3][4][5][10]。プロミスは、非同期処理の完了を表現するオブジェクトであり、成功または失敗の結果を表す。プロミスはコールバックよりも直感的で、チェーン可能な構造をもち、エラーハンドリングも容易である。しかし、プロミスにも限界がある。複数のプロミスを組み合わせた複雑な処理を管理する際には、依然としてコードが冗長になりがちであり、エラーハンドリングが煩雑になることがある。
async/awaitの必要性
[編集]async/awaitは、コールバックとプロミスの限界を克服するために設計された構文である[1][2][4][7]。async/awaitを使用することで、非同期コードはまるで同期コードのように見え、直感的に理解しやすくなる。具体的には、async
キーワードを使用して非同期関数を定義し、その関数内でawait
キーワードを使用して非同期処理の完了を待つことができる。これにより、非同期処理の結果を同期的に処理することが可能になり、コードの可読性と保守性が大幅に向上する。
async/awaitは、特に複数の非同期処理を連続して実行する必要がある場合に有効である[1][4][5][7]。従来のコールバックやプロミスを使用した方法では、これらの処理を管理するのが困難であったが、async/awaitを使用することで、コードがシンプルで明確になる。また、エラーハンドリングもtry...catch
構文を使用して同期コードと同様に行うことができるため、非同期処理のエラーハンドリングが一貫して行える。
async/awaitは、非同期処理をより簡単かつ効率的に行うための強力なツールであり、現代のプログラミングにおいて欠かせない技術となっている。これにより、開発者はより直感的で保守しやすい非同期コードを記述することができ、システム全体のパフォーマンスとユーザーエクスペリエンスを向上させることが可能となる。
歴史
[編集]初期の非同期プログラミング
[編集]非同期プログラミングの歴史は、コンピュータサイエンスの初期にまで遡ることができる[11][12][13][14]。初期のコンピュータシステムでは、同期的にタスクを処理することが一般的であり、全ての処理は直列に実行されていた。しかし、コンピュータの性能が向上し、より複雑なシステムが求められるようになると、非同期的な処理が必要とされるようになった。特に、入出力処理やネットワーク通信など、時間のかかるタスクを効率的に処理するためには、非同期プログラミングが不可欠となった。初期の非同期プログラミングでは、割り込み処理やイベント駆動型プログラミングが主流であり、コールバックを利用して非同期イベントに対応していた。
async/awaitの登場
[編集]async/awaitの登場は、非同期プログラミングにおける大きな進化を意味する[1][2][4][15]。コールバックやプロミスを用いた従来の非同期プログラミングの手法は、コードの可読性と保守性に課題があった。これらの課題を解決するために、より直感的で分かりやすい非同期プログラミングの手法が求められていた。async/awaitは、そのような背景から登場したもので、非同期処理をまるで同期処理のように記述できる構文を提供する。最初にasync/awaitを導入した言語の一つがC#であり、2012年にリリースされたC# 5.0で初めて搭載された[7][15]。その後、他の主要なプログラミング言語でもasync/awaitが採用されるようになり、非同期プログラミングの標準的な手法として定着していった[1][4][16][17][18]。
各言語での導入時期
[編集]async/awaitは、複数のプログラミング言語で順次導入されてきた。以下に、主要な言語での導入時期を時系列で示す。
- C#[7][15]:async/awaitはC# 5.0(2012年)で初めて導入された。これにより、C#の開発者は非同期処理を同期的なコードのように記述できるようになった。
- Python[1][2]:Pythonでは、async/awaitはPython 3.5(2015年)で導入された。Pythonコミュニティは、この機能を歓迎し、広範に利用するようになった。
- JavaScript[4][5]:JavaScriptでは、async/awaitはECMAScript 2017(ES8)で標準化された。これにより、JavaScriptの開発者も非同期コードを簡潔に記述できるようになった。
- Kotlin[16][19]:Kotlinでは、async/awaitに相当する機能として、コルーチンが導入された。Kotlin 1.1(2017年)で公式にサポートされるようになった。
- Rust[17][20]:Rustでは、async/awaitはRust 1.39(2019年)で導入された。Rustの特徴である安全性とパフォーマンスを保ちながら、非同期処理が容易になった。
- Swift[18]:Swiftでは、async/awaitはSwift 5.5(2021年)で導入された。これにより、Swiftの開発者も非同期処理を同期コードのように記述できるようになった。
このように、async/awaitは多くのプログラミング言語で採用され、現代の非同期プログラミングの標準的な手法となっている。それぞれの言語での導入時期や具体的な実装には若干の違いがあるものの、async/awaitの基本的な概念と利便性は共通している。
構文と使い方
[編集]基本構文
[編集]async/awaitの基本構文は、非同期関数を定義するためのasync
キーワードと、その関数内で非同期処理の完了を待つためのawait
キーワードから成り立っている[1][2]。非同期関数は、async
キーワードを付けることで定義され、その関数内でawait
キーワードを使用することで、非同期処理の完了を待つことができる。以下に、Pythonの基本的な構文を示す。
async def 非同期関数():
結果 = await 非同期操作()
return 結果
この構文により、非同期処理の結果を同期的に処理することが可能となり、コードの可読性が向上する。
非同期関数の定義
[編集]非同期関数は、async
キーワードを使って定義される[1][2]。このキーワードを関数定義の前に付けることで、その関数が非同期関数であることを示す。非同期関数内では、await
キーワードを使って非同期処理の完了を待つことができる。以下に、Pythonでの非同期関数の定義例を示す。
import asyncio
async def 非同期関数():
print("非同期処理開始")
await asyncio.sleep(1) # 非同期の遅延処理をシミュレート
print("非同期処理完了")
# イベントループを使用して非同期関数を実行
asyncio.run(非同期関数())
この例では、asyncio
モジュールを使用して非同期関数を定義し、イベントループによって非同期関数を実行している。非同期関数内でawait
キーワードを使用することで、非同期処理の完了を待っている。
awaitキーワードの使い方
[編集]await
キーワードは、非同期処理の完了を待つために使用される[1][2]。非同期関数内でのみ使用可能であり、通常は非同期関数や非同期処理を返す関数の前に付けて使う。以下に、Pythonでのawait
キーワードの基本的な使い方を示す。
import asyncio
async def 非同期操作():
await asyncio.sleep(1)
return "操作完了"
async def 非同期関数():
結果 = await 非同期操作()
print(結果)
asyncio.run(非同期関数())
この例では、非同期処理を行う関数をawait
キーワードで待ち、処理が完了した後に結果を処理している。
エラーハンドリング
[編集]非同期関数内でエラーハンドリングを行うためには、Pythonでは通常の同期コードと同様にtry...except
ブロックを使用する[1][2]。これにより、非同期処理中に発生した例外を捕捉し、適切に処理することができる。以下に、非同期関数内でのエラーハンドリングの例を示す。
import asyncio
async def 非同期操作():
await asyncio.sleep(1)
raise Exception("エラー発生")
async def 非同期関数():
try:
結果 = await 非同期操作()
print(結果)
except Exception as e:
print("例外をキャッチ:", str(e))
asyncio.run(非同期関数())
この例では、非同期処理中に例外が発生した場合にtry...except
ブロックでその例外を捕捉し、エラーメッセージを表示している。これにより、非同期処理中のエラーも一貫してハンドリングできる。
このように、async/awaitは基本構文と使い方を理解することで、非同期処理を直感的に記述できる強力なツールである。非同期関数の定義、await
キーワードの使い方、エラーハンドリングを組み合わせることで、非同期処理を効率的に行うことができる。
プログラミング言語別実装
[編集]async/awaitは様々なプログラミング言語で導入されている。以下に、主要な各言語での使い方と簡単な具体例を示す。
C言語
[編集]構文と使い方
[編集]C言語には、他の言語のような組み込みのasync/await構文は存在しない[21][22]。非同期処理を実現するためには、POSIXスレッド(pthread
)やコールバック関数、イベントループを使用することが一般的である。非同期処理の基本的な構文は、スレッドの作成やコールバック関数の使用を通じて実現される。以下は、pthread
を使用した非同期関数の基本的な構文である。
#include <pthread.h>
#include <stdio.h>
void* 非同期操作(void* arg) {
// 非同期操作の実装
return NULL;
}
void 非同期関数() {
pthread_t スレッド;
pthread_create(&スレッド, NULL, 非同期操作, NULL);
pthread_detach(スレッド); // スレッドのデタッチ
}
この構文により、非同期処理を別のスレッドで実行することができる。
具体例
[編集]C言語での具体的な使用例を示す。以下の例では、pthread
を用いて非同期にデータを処理し、その結果をメインスレッドで処理している。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// 非同期操作の実装
void* 非同期操作(void* arg) {
char* url = (char*)arg;
sleep(2); // データの取得をシミュレート
printf("データ取得完了: %s\n", url);
return NULL;
}
void 非同期関数(const char* url) {
pthread_t スレッド;
char* スレッド引数 = strdup(url); // スレッド引数のコピーを作成
if (pthread_create(&スレッド, NULL, 非同期操作, (void*)スレッド引数) != 0) {
perror("スレッド作成エラー");
free(スレッド引数);
return;
}
pthread_detach(スレッド); // スレッドのデタッチ
}
int main() {
const char* url = "https://api.example.com/data";
非同期関数(url);
// メインスレッドで他の作業を行う
printf("メインスレッドの作業\n");
sleep(3); // メインスレッドの待機
return 0;
}
この例では、pthread_create
を用いて非同期にデータを処理し、pthread_detach
でスレッドをデタッチしている。非同期処理が完了した後、結果が表示される。
利用可能な環境
[編集]C言語での非同期処理は、POSIX標準に準拠した環境で広く利用可能である。以下の環境で利用可能である。
- Linux[23]:POSIXスレッド(
pthread
)ライブラリが標準でサポートされている。 - macOS[24]:POSIXスレッド(
pthread
)ライブラリが標準でサポートされている。 - Windows[25]:POSIX互換レイヤー(CygwinやWSLなど)を使用して利用可能。また、WindowsスレッドAPIを使用することもできる。
これらの環境では、POSIXスレッドを使用して非同期処理を実装することができる。標準のCライブラリを使用することで、非同期処理を柔軟に実現できるため、C言語の非同期処理は幅広いプラットフォームで利用可能である。これにより、非同期コードの可読性と保守性を高め、効率的な非同期プログラミングを行うことができる。
C++
[編集]構文と使い方
[編集]C++におけるasync/awaitの構文は、C++20で導入されたコルーチン(coroutines)を使用して実現される[26][27]。非同期関数を定義するためには、co_await
キーワードを使用して非同期処理の完了を待機する。また、非同期関数にはco_return
を使用して結果を返す。非同期関数はco_await
を含むことでコルーチンとして扱われ、std::future
やstd::promise
などの標準ライブラリと連携して非同期処理を行う。基本的な構文は以下の通りである。
#include <future>
std::future<int> 非同期関数() {
co_await std::async(std::launch::async, []() {
// 非同期操作
return 42;
});
co_return 42;
}
この構文により、非同期処理を同期的なコードのように記述でき、コードの可読性が向上する。
具体例
[編集]C++での具体的な使用例を示す。以下の例では、非同期にデータを取得し、その結果を処理している。
#include <iostream>
#include <future>
#include <string>
#include <thread>
#include <chrono>
std::future<std::string> 取得データ(std::string url) {
// 非同期にデータを取得する操作をシミュレート
co_await std::async(std::launch::async, [url]() {
std::this_thread::sleep_for(std::chrono::seconds(2));
return "データ: " + url;
});
co_return "データ: " + url;
}
int main() {
auto データタスク = 取得データ("https://api.example.com/data");
データタスク.wait(); // データの取得を待機
try {
std::string データ = データタスク.get();
std::cout << "取得したデータ: " << データ << std::endl;
} catch (const std::exception& エラー) {
std::cout << "データの取得中にエラーが発生しました: " << エラー.what() << std::endl;
}
return 0;
}
この例では、非同期にデータを取得する処理をシミュレートし、std::async
とco_await
を使用して非同期処理の完了を待機している。取得したデータを処理し、try...catch
ブロックを用いてエラーハンドリングを行っている。
利用可能な環境
[編集]C++のコルーチン(async/await)は、C++20で導入されており、対応するコンパイラと標準ライブラリが必要である。以下の環境で利用可能である。
これらの環境では、C++20の機能を有効にするために適切なフラグを指定する必要がある。例えば、GCCでは-std=c++20
フラグを使用する。
このように、C++のasync/awaitは幅広い環境で利用可能であり、非同期処理を簡潔かつ直感的に記述できるため、C++開発者にとって非常に有用なツールとなっている。これにより、非同期コードの可読性と保守性が大幅に向上し、エラーハンドリングも一貫して行うことができる。
Python
[編集]構文と使い方
[編集]Pythonにおけるasync/awaitの構文は、非常に直感的であり、非同期関数を定義するためにasync
キーワードを使用し、その関数内で非同期処理を待機するためにawait
キーワードを使用する[1][2]。非同期関数は、async
キーワードを付けることで定義され、その関数内ではawait
キーワードを使用して、非同期処理の完了を待つことができる。基本的な構文は以下の通りである。
async def 非同期関数():
結果 = await 非同期操作()
return 結果
この構文により、非同期処理を同期的に処理することが可能となり、コードの可読性が向上する。
具体例
[編集]Pythonでの具体的な使用例を示す。以下の例では、非同期にデータを取得し、その結果を処理している。
import asyncio
import aiohttp
async def 取得データ(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
if response.status != 200:
raise Exception("ネットワーク応答が正常ではありません")
データ = await response.json() # 応答をJSONとして解析
return データ
async def main():
try:
データ = await 取得データ("https://api.example.com/data")
print("取得したデータ:", データ)
except Exception as エラー:
print("データの取得中にエラーが発生しました:", エラー)
# イベントループを使用して非同期関数を実行
asyncio.run(main())
この例では、aiohttp
ライブラリを用いて非同期にデータを取得し、取得したデータをJSONとして解析している。また、try...except
ブロックを用いてエラーハンドリングを行い、エラーが発生した場合には適切なメッセージを表示する。
利用可能な環境
[編集]Pythonのasync/awaitは、Python 3.5以降で標準機能としてサポートされている。以下の環境で利用可能である。
Python 3.5以降のバージョンでは、標準ライブラリのasyncio
モジュールがasync/awaitをサポートしており、非同期プログラミングを行うための基盤を提供している。また、aiohttp
やtrio
といったサードパーティライブラリもasync/awaitを活用した非同期処理をサポートしている。
このように、Pythonのasync/awaitは幅広い環境で利用可能であり、非同期処理を簡潔かつ直感的に記述できるため、Python開発者にとって非常に有用なツールとなっている。これにより、非同期コードの可読性と保守性が大幅に向上し、エラーハンドリングも一貫して行うことができる。
JavaScript
[編集]構文と使い方
[編集]JavaScriptにおけるasync/awaitの構文は非常にシンプルで、非同期関数を定義するためにasync
キーワードを使用し、その関数内で非同期処理を待機するためにawait
キーワードを使用する[4][5]。非同期関数は常にプロミス(Promise)を返し、await
キーワードはそのプロミスが解決されるまで待機する。基本的な構文は以下の通りである。
async function 非同期関数() {
const 結果 = await 非同期操作();
return 結果;
}
この構文により、非同期処理をまるで同期コードのように記述することができ、コードの可読性が向上する。
具体例
[編集]JavaScriptでの具体的な使用例を示す。以下の例では、fetch
関数を用いて非同期にデータを取得し、その結果を処理している。
async function 取得データ(url) {
try {
const 応答 = await fetch(url); // 非同期にデータを取得
if (!応答.ok) {
throw new Error("ネットワーク応答が正常ではありません");
}
const データ = await 応答.json(); // 応答をJSONとして解析
return データ;
} catch (エラー) {
console.error("データの取得中にエラーが発生しました:", エラー);
throw エラー;
}
}
取得データ("https://api.example.com/data")
.then(データ => {
console.log("取得したデータ:", データ);
})
.catch(エラー => {
console.error("エラーハンドリング:", エラー);
});
この例では、fetch
関数をawait
キーワードで待機し、データの取得が完了するまでコードの実行を一時停止する。その後、取得したデータをJSONとして解析し、処理する。また、try...catch
ブロックを用いてエラーハンドリングを行っている。
利用可能な環境
[編集]JavaScriptのasync/awaitは、ECMAScript 2017(ES8)で標準化され、多くのモダンなウェブブラウザやJavaScriptランタイム環境で利用可能である。具体的には以下の環境でサポートされている。
- モダンブラウザ:Google Chrome、Mozilla Firefox、Safari、Microsoft Edgeなどの最新バージョン。
- Node.js[30]:バージョン7.6以降でサポートされている。
このように、async/awaitは幅広い環境で利用可能であり、非同期処理を簡潔に記述できるため、JavaScript開発者にとって非常に有用なツールとなっている。これにより、非同期コードの可読性と保守性が大幅に向上し、エラーハンドリングも一貫して行うことができる。
C#
[編集]構文と使い方
[編集]C#におけるasync/awaitの構文は、非同期関数を定義するためにasync
キーワードを使用し、その関数内で非同期処理を待機するためにawait
キーワードを使用する[7][15]。非同期関数はTask
またはTask<T>
を返し、await
キーワードは非同期処理が完了するまで待機する。基本的な構文は以下の通りである。
public async Task<T> 非同期関数()
{
T 結果 = await 非同期操作();
return 結果;
}
この構文により、非同期処理を同期的なコードのように記述でき、コードの可読性が向上する。
具体例
[編集]C#での具体的な使用例を示す。以下の例では、HttpClient
を用いて非同期にデータを取得し、その結果を処理している。
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class プログラム
{
public static async Task Main(string[] args)
{
try
{
var データ = await 取得データAsync("https://api.example.com/data");
Console.WriteLine("取得したデータ: " + データ);
}
catch (Exception エラー)
{
Console.WriteLine("データの取得中にエラーが発生しました: " + エラー.Message);
}
}
public static async Task<string> 取得データAsync(string url)
{
using (HttpClient クライアント = new HttpClient())
{
HttpResponseMessage 応答 = await クライアント.GetAsync(url); // 非同期にデータを取得
応答.EnsureSuccessStatusCode();
string データ = await 応答.Content.ReadAsStringAsync(); // 応答を文字列として解析
return データ;
}
}
}
この例では、HttpClient
を用いて非同期にデータを取得し、取得したデータを文字列として解析している。また、try...catch
ブロックを用いてエラーハンドリングを行い、エラーが発生した場合には適切なメッセージを表示している。
利用可能な環境
[編集]C#のasync/awaitは、.NET Framework 4.5以降および.NET Core 1.0以降で標準機能としてサポートされている。以下の環境で利用可能である。
- .NET Framework[15]:バージョン4.5以降。
- .NET Core[6]:バージョン1.0以降。
- .NET 5/6/7[31]:最新バージョン。
- Xamarin[32]:サポートされている。
- Unity[33]:2018.3以降のバージョン。
このように、C#のasync/awaitは幅広い環境で利用可能であり、非同期処理を簡潔かつ直感的に記述できるため、C#開発者にとって非常に有用なツールとなっている。これにより、非同期コードの可読性と保守性が大幅に向上し、エラーハンドリングも一貫して行うことができる。
F#
[編集]構文と使い方
[編集]F#におけるasync/awaitの構文は、async
キーワードを使用して非同期ワークフローを定義し、そのワークフロー内でlet!
キーワードを使用して非同期処理を待機する[34][35]。F#の非同期ワークフローは、async
モジュールによってサポートされており、非同期処理を直感的に記述することができる。基本的な構文は以下の通りである。
open System.Net.Http
let 非同期関数() =
async {
let! 応答 = Async.AwaitTask (非同期操作())
return 応答
}
この構文により、非同期処理を同期的なコードのように記述でき、コードの可読性が向上する。
具体例
[編集]F#での具体的な使用例を示す。以下の例では、HttpClient
を用いて非同期にデータを取得し、その結果を処理している。
open System
open System.Net.Http
open System.Threading.Tasks
let 取得データ (url: string) =
async {
use クライアント = new HttpClient()
let! 応答 = クライアント.GetAsync(url) |> Async.AwaitTask // 非同期にデータを取得
応答.EnsureSuccessStatusCode() |> ignore
let! データ = 応答.Content.ReadAsStringAsync() |> Async.AwaitTask // 応答を文字列として解析
return データ
}
[<EntryPoint>]
let main argv =
let url = "https://api.example.com/data"
let データタスク = 取得データ url |> Async.StartAsTask
データタスク.ContinueWith(fun t ->
match t.Status with
| TaskStatus.RanToCompletion ->
printfn "取得したデータ: %s" t.Result
| TaskStatus.Faulted ->
printfn "データの取得中にエラーが発生しました: %s" t.Exception.Message
| _ -> ()
) |> ignore
// メインスレッドを保持するための処理
Console.ReadLine() |> ignore
0
この例では、HttpClient
を用いて非同期にデータを取得し、取得したデータを文字列として解析している。また、非同期ワークフロー内でlet!
キーワードを使用して非同期処理の完了を待機し、タスクを開始して結果を処理している。
利用可能な環境
[編集]F#のasync/awaitは、.NET Framework 4.5以降、.NET Core 1.0以降、および最新の.NETバージョンでサポートされている。また、F#は他の.NET言語と同様に、様々な環境で利用可能である。
- .NET Framework[34]:バージョン4.5以降。
- .NET Core[34]:バージョン1.0以降。
- .NET 5/6/7[35]:最新バージョン。
- Xamarin[32]:サポートされている。
- Unity[33]:サポートされている。
このように、F#のasync/awaitは幅広い環境で利用可能であり、非同期処理を簡潔かつ直感的に記述できるため、F#開発者にとって非常に有用なツールとなっている。これにより、非同期コードの可読性と保守性が大幅に向上し、エラーハンドリングも一貫して行うことができる。
Rust
[編集]構文と使い方
[編集]Rustにおけるasync/awaitの構文は、非常に直感的であり、非同期関数を定義するためにasync
キーワードを使用し、その関数内で非同期処理を待機するためにawait
キーワードを使用する[17][20]。非同期関数はFuture
トレイトを実装し、非同期処理を行うための基本的な構文は以下の通りである。
async fn 非同期関数() -> Result<T, E> {
let 結果 = 非同期操作().await;
Ok(結果)
}
この構文により、非同期処理を同期的なコードのように記述でき、コードの可読性が向上する。
具体例
[編集]Rustでの具体的な使用例を示す。以下の例では、reqwest
クレートを用いて非同期にデータを取得し、その結果を処理している。
use reqwest::Error;
use tokio; // Tokioランタイムを使用
async fn 取得データ(url: &str) -> Result<String, Error> {
let 応答 = reqwest::get(url).await?; // 非同期にデータを取得
let データ = 応答.text().await?; // 応答を文字列として解析
Ok(データ)
}
#[tokio::main]
async fn main() {
match 取得データ("https://api.example.com/data").await {
Ok(データ) => println!("取得したデータ: {}", データ),
Err(エラー) => println!("データの取得中にエラーが発生しました: {}", エラー),
}
}
この例では、reqwest
クレートを用いて非同期にデータを取得し、取得したデータを文字列として解析している。また、tokio
ランタイムを使用して非同期関数を実行している。try...catch
に相当するmatch
構文を用いてエラーハンドリングを行っている。
利用可能な環境
[編集]Rustのasync/awaitは、Rust 1.39以降で標準機能としてサポートされている。以下の環境で利用可能である。
- Rust[20]:バージョン1.39以降。
- Tokio[20]:非同期ランタイムとして広く使用されている。
- async-std[20]:別の非同期ランタイムであり、標準ライブラリのようなAPIを提供。
これらの環境では、非同期処理を簡潔かつ直感的に記述することができる。Rustのasync/awaitは、幅広い環境で利用可能であり、非同期コードの可読性と保守性を大幅に向上させる。また、Tokioやasync-stdといった非同期ランタイムを使用することで、効率的な非同期プログラミングが可能となる。これにより、Rust開発者は高性能な非同期アプリケーションを構築することができる。
Kotlin
[編集]構文と使い方
[編集]Kotlinにおけるasync/awaitの構文は、コルーチンを使用して実現される[16][19]。コルーチンは、非同期プログラミングを簡潔かつ直感的に記述するための強力な機能である。非同期関数を定義するためには、suspend
キーワードを使用し、その関数内で非同期処理を待機するためにawait
キーワードに相当するawait
関数を使用する。基本的な構文は以下の通りである。
import kotlinx.coroutines.*
suspend fun 非同期関数(): T {
val 結果 = 非同期操作().await()
return 結果
}
この構文により、非同期処理を同期的なコードのように記述でき、コードの可読性が向上する。
具体例
[編集]Kotlinでの具体的な使用例を示す。以下の例では、kotlinx.coroutines
ライブラリを用いて非同期にデータを取得し、その結果を処理している。
import kotlinx.coroutines.*
import java.net.URL
suspend fun 取得データ(url: String): String = withContext(Dispatchers.IO) {
URL(url).readText()
}
fun main() = runBlocking {
try {
val データ = 取得データ("https://api.example.com/data")
println("取得したデータ: $データ")
} catch (エラー: Exception) {
println("データの取得中にエラーが発生しました: ${エラー.message}")
}
}
この例では、withContext
関数を用いて非同期にデータを取得し、取得したデータを文字列として解析している。また、runBlocking
関数を使用してメインスレッドでコルーチンを実行し、try...catch
ブロックを用いてエラーハンドリングを行っている。
利用可能な環境
[編集]Kotlinのコルーチン(async/await)は、Kotlin 1.3以降で標準機能としてサポートされている。以下の環境で利用可能である。
- JVM[16]:KotlinのコルーチンはJVM上で動作する。
- Android[36]:Androidアプリケーションで広く使用されている。
- JavaScript[19]:Kotlin/JSでもコルーチンを使用可能。
- Native[19]:Kotlin/Nativeでもコルーチンをサポート。
これらの環境では、kotlinx.coroutines
ライブラリを使用して非同期処理を簡潔かつ直感的に記述することができる。Kotlinのコルーチンは、幅広い環境で利用可能であり、非同期コードの可読性と保守性を大幅に向上させる。また、コルーチンを使用することで、効率的な非同期プログラミングが可能となる。これにより、Kotlin開発者は高性能な非同期アプリケーションを構築することができる。
Swift
[編集]構文と使い方
[編集]Swiftにおけるasync/awaitの構文は、非同期関数を定義するためにasync
キーワードを使用し、その関数内で非同期処理を待機するためにawait
キーワードを使用する[37][38]。非同期関数は、async
キーワードを付けることで定義され、その関数内ではawait
キーワードを使用して非同期処理の完了を待つことができる。基本的な構文は以下の通りである。
func 非同期関数() async throws -> T {
let 結果 = try await 非同期操作()
return 結果
}
この構文により、非同期処理を同期的なコードのように記述でき、コードの可読性が向上する。
具体例
[編集]Swiftでの具体的な使用例を示す。以下の例では、非同期にデータを取得し、その結果を処理している。
import Foundation
func 取得データ(from url: URL) async throws -> String {
let (データ, _) = try await URLSession.shared.data(from: url)
return String(data: データ, encoding: .utf8) ?? "データの解析に失敗しました"
}
@main
struct 非同期プログラム {
static func main() async {
let url = URL(string: "https://api.example.com/data")!
do {
let データ = try await 取得データ(from: url)
print("取得したデータ: \(データ)")
} catch {
print("データの取得中にエラーが発生しました: \(error.localizedDescription)")
}
}
}
この例では、URLSession
を用いて非同期にデータを取得し、取得したデータを文字列として解析している。try await
構文を用いて非同期処理を待機し、エラーハンドリングを行っている。
利用可能な環境
[編集]Swiftのasync/awaitは、Swift 5.5以降で標準機能としてサポートされている。以下の環境で利用可能である。
- iOS:iOS 15以降。
- macOS:macOS 12 Monterey以降。
- tvOS:tvOS 15以降。
- watchOS:watchOS 8以降。
これらの環境では、async/awaitを使用して非同期処理を簡潔かつ直感的に記述することができる。Swiftのasync/awaitは、幅広い環境で利用可能であり、非同期コードの可読性と保守性を大幅に向上させる。また、非同期処理を同期的なコードのように記述することで、効率的な非同期プログラミングが可能となる。これにより、Swift開発者は高性能な非同期アプリケーションを構築することができる。
メリットとデメリット
[編集]async/awaitは多くのメリットをもつ一方、いくつかのデメリットも存在する。以下に詳述する。
メリット
[編集]- 可読性の向上[4][15][17]:async/awaitの最大のメリットは、コードの可読性が大幅に向上することである。従来のコールバックやプロミスを使用した非同期処理は、ネストが深くなりがちであり、いわゆる「コールバック地獄」を引き起こす。これに対して、async/awaitを使用することで、非同期処理をまるで同期処理のように記述でき、コードのフローが直感的に理解しやすくなる。これにより、開発者がコードを読みやすくし、保守しやすくなる。
- デバッグの容易さ[1][6][5]:async/awaitを使用することで、デバッグが容易になる。非同期コードが同期コードと同様のフローで記述されるため、デバッグツールを使用してステップ毎に実行状況を確認することができる。また、例外処理も同期コードと同様に
try...catch
ブロックを使用して行うことができるため、非同期処理中に発生するエラーを一貫してハンドリングすることが可能である。 - パフォーマンス[15][17][30]:async/awaitは、システムリソースの効率的な利用を促進し、パフォーマンスの向上に寄与する。非同期処理を使用することで、I/O処理やネットワーク通信などの時間のかかる処理を非ブロッキングで実行できるため、システム全体の応答性が向上する。特に、複数の非同期処理を並行して実行する場合、システムのスループットを最大化することができる。
デメリット
[編集]- 学習曲線[15][17][39]:async/awaitの使用には、一定の学習曲線が伴う。特に、従来の同期的なプログラミングに慣れている開発者にとって、非同期プログラミングの概念やasync/awaitの使い方を理解するのには時間がかかる場合がある。また、非同期処理に関連するエラーハンドリングやリソース管理のベストプラクティスを習得する必要がある。
- サポートするランタイムの制限[4][6][17]:async/awaitは、言語やランタイム環境によってサポート状況が異なる。最新の言語仕様やランタイムではサポートされていることが多いが、古いバージョンの言語や特定のランタイム環境ではサポートされていない場合がある。このため、async/awaitを利用するためには、開発環境やデプロイ環境が最新の仕様に対応していることを確認する必要がある。また、特定のプラットフォームやライブラリがasync/awaitをサポートしていない場合、それに代わる手法を検討する必要がある。
これらのメリットとデメリットを考慮することで、async/awaitの活用により非同期プログラミングの効果を最大化し、適切なエラーハンドリングとパフォーマンスの最適化を図ることができる。
具体的な使用例
[編集]Web開発における使用例
[編集]async/awaitは、Web開発において非常に有用である。例えば、Webサーバーがクライアントからのリクエストを処理する際に、データベースや外部APIからデータを取得する場合、これらの処理を非同期的に行うことで、サーバーの応答性を向上させることができる。以下は、Node.jsとExpressを使用した具体的なJavaScriptの例である。
const express = require('express');
const fetch = require('node-fetch');
const app = express();
app.get('/data', async (req, res) => {
try {
const response = await fetch('https://api.example.com/data'); // 非同期に外部APIからデータを取得
const data = await response.json(); // 取得したデータをJSONとして解析
res.json(data);
} catch (error) {
res.status(500).send('データの取得中にエラーが発生しました: ' + error.message);
}
});
app.listen(3000, () => {
console.log('サーバーがポート3000で起動しました');
});
この例では、外部APIから非同期にデータを取得し、取得したデータをクライアントに返している。await
キーワードを使用することで、非同期処理を同期的なコードのように記述している。
データベースアクセスの非同期化
[編集]データベースアクセスも非同期化することで、アプリケーションのパフォーマンスを向上させることができる。以下は、Pythonとasyncpg
ライブラリを使用した非同期データベースアクセスの具体例である。
import asyncio
import asyncpg
async def 取得データ():
conn = await asyncpg.connect(user='user', password='password', database='database', host='127.0.0.1')
rows = await conn.fetch('SELECT * FROM table')
await conn.close()
return rows
async def main():
try:
データ = await 取得データ()
for row in データ:
print(row)
except Exception as エラー:
print('データベースアクセス中にエラーが発生しました:', エラー)
asyncio.run(main())
この例では、asyncpg
ライブラリを使用して非同期にデータベースからデータを取得し、結果を処理している。データベースアクセスを非同期化することで、他のI/O処理がブロックされることなく、効率的にデータを処理することができる。
入出力処理の最適化
[編集]ファイルの読み書きなどの入出力処理も、非同期化することでアプリケーションのパフォーマンスを向上させることができる。以下は、C#とSystem.IO
ライブラリを使用した非同期ファイル読み書きの具体例である。
using System;
using System.IO;
using System.Threading.Tasks;
class プログラム
{
public static async Task ファイル読み込み(string filePath)
{
try
{
using (StreamReader reader = new StreamReader(filePath))
{
string content = await reader.ReadToEndAsync(); // 非同期にファイルを読み込む
Console.WriteLine("ファイル内容: " + content);
}
}
catch (Exception エラー)
{
Console.WriteLine("ファイル読み込み中にエラーが発生しました: " + エラー.Message);
}
}
public static async Task ファイル書き込み(string filePath, string content)
{
try
{
using (StreamWriter writer = new StreamWriter(filePath))
{
await writer.WriteAsync(content); // 非同期にファイルに書き込む
Console.WriteLine("ファイルに書き込みました");
}
}
catch (Exception エラー)
{
Console.WriteLine("ファイル書き込み中にエラーが発生しました: " + エラー.Message);
}
}
public static async Task Main(string[] args)
{
string path = "example.txt";
await ファイル書き込み(path, "これは非同期書き込みの例です。");
await ファイル読み込み(path);
}
}
この例では、非同期にファイルを読み書きすることで、I/O処理中に他の処理がブロックされることなく、効率的にファイル処理を行っている。これにより、アプリケーションの応答性が向上し、ユーザーエクスペリエンスが改善される。
ベストプラクティス
[編集]async/awaitは非同期処理を必要とするアプリケーションにおいて強力なツールである。以下に、async/awaitを効果的に導入するためのベストプラクティスをいくつか紹介する。
適切なエラーハンドリング
[編集]async/awaitを使用する際には、適切なエラーハンドリングが重要である[1][2]。非同期処理中にエラーが発生する可能性があるため、try...except
(try...catch
に対応)ブロックを使用して例外を捕捉し、適切に対処する必要がある。以下に、Pythonでの例を示す。
import asyncio
async def 非同期操作():
await asyncio.sleep(1)
raise Exception("エラー発生")
async def main():
try:
await 非同期操作()
except Exception as e:
print(f"エラーが発生しました: {e}")
asyncio.run(main())
この例では、非同期処理中にエラーが発生した場合に、try...except
ブロックで例外を捕捉し、エラーメッセージを表示している。これにより、非同期処理中のエラーを一貫してハンドリングすることができる。
リソース管理
[編集]非同期処理では、リソースの適切な管理が重要である[15][39]。ファイルやネットワーク接続などのリソースは、使用後に必ず解放する必要がある。以下に、C#での例を示す。
using System;
using System.IO;
using System.Threading.Tasks;
class プログラム
{
public static async Task ファイル操作(string filePath)
{
try
{
using (StreamReader reader = new StreamReader(filePath))
{
string content = await reader.ReadToEndAsync();
Console.WriteLine(content);
}
}
catch (Exception e)
{
Console.WriteLine($"エラーが発生しました: {e.Message}");
}
}
public static async Task Main(string[] args)
{
await ファイル操作("example.txt");
}
}
この例では、using
ステートメントを使用してファイルリソースを管理している。ファイルの処理が終了すると、StreamReader
が自動的に解放される。これにより、リソースリークを防ぐことができる。
パフォーマンスの最適化
[編集]非同期処理のパフォーマンスを最適化するためには、並行処理を適切に利用することが重要である[4][30]。複数の非同期処理を同時に実行することで、システムのスループットを最大化することができる。以下に、JavaScriptでの例を示す。
async function 非同期操作1() {
return new Promise(resolve => setTimeout(() => resolve("結果1"), 1000));
}
async function 非同期操作2() {
return new Promise(resolve => setTimeout(() => resolve("結果2"), 1000));
}
async function main() {
const [結果1, 結果2] = await Promise.all([非同期操作1(), 非同期操作2()]);
console.log(結果1, 結果2);
}
main();
この例では、Promise.all
を使用して複数の非同期処理を同時に実行している。これにより、全体の処理時間を短縮し、パフォーマンスを最適化している。
コードの分割とモジュール化
[編集]非同期処理を含むコードは、モジュール化して分割することで、可読性と保守性を向上させることができる[1][2]。大きな関数を小さな関数に分割し、それぞれの関数が単一の責任をもつように設計することが推奨される。以下に、Pythonでの例を示す。
import asyncio
async def データ取得(url):
print(f"{url}からデータを取得しています...")
await asyncio.sleep(1)
return f"{url}のデータ"
async def データ処理(url):
データ = await データ取得(url)
print(f"取得したデータ: {データ}")
async def main():
urls = ["https://example.com/data1", "https://example.com/data2"]
タスク = [データ処理(url) for url in urls]
await asyncio.gather(*タスク)
asyncio.run(main())
この例では、データ取得とデータ処理のロジックを別々の関数に分割している。これにより、各関数の役割が明確になり、コードの可読性と保守性が向上する。
これらのベストプラクティスを守ることで、async/awaitを用いた非同期プログラミングの効果を最大限に引き出し、安定した高性能なアプリケーションを構築することができる。
よくある問題と解決策
[編集]以下に、async/awaitを導入する際に発生しがちな、一般的なよくある問題とその解決策を詳述する。
デッドロックの回避
[編集]デッドロックは、複数の非同期処理が相互に待機状態になることで発生する問題である[1][2]。デッドロックを回避するためには、リソースの取得順序を一貫させることが重要である。また、非同期関数を呼び出す際には、await
キーワードを正しい場所で使用し、他の非同期処理をブロックしないようにする必要がある。以下に、Pythonでの例を示す。
import asyncio
import threading
lock1 = threading.Lock()
lock2 = threading.Lock()
async def タスク1():
async with lock1:
await asyncio.sleep(1)
async with lock2:
print("タスク1 完了")
async def タスク2():
async with lock2:
await asyncio.sleep(1)
async with lock1:
print("タスク2 完了")
async def main():
await asyncio.gather(タスク1(), タスク2())
asyncio.run(main())
この例では、async with
構文を使用してリソースの取得順序を一貫させ、デッドロックを回避している。
スレッドの管理
[編集]非同期処理では、スレッドの適切な管理が重要である[1][2]。非同期関数がブロッキング処理を含む場合、スレッドプールを使用してブロッキング処理を別のスレッドで実行することで、メインスレッドのブロックを防ぐことができる。以下に、Pythonでの例を示す。
import asyncio
import concurrent.futures
def ブロッキング操作():
import time
time.sleep(3)
return "完了"
async def main():
loop = asyncio.get_running_loop()
with concurrent.futures.ThreadPoolExecutor() as pool:
結果 = await loop.run_in_executor(pool, ブロッキング操作)
print(結果)
asyncio.run(main())
この例では、concurrent.futures.ThreadPoolExecutor
を使用して、ブロッキング処理を別のスレッドで実行し、メインスレッドのブロックを防いでいる。
非同期処理のデバッグ
[編集]非同期処理のデバッグは、同期処理に比べて難しいことが多い[4][5]。非同期コードの実行フローが複雑になるため、適切なデバッグツールと技法を使用することが重要である。以下に、JavaScriptでの例を示す。
async function 非同期操作() {
try {
console.log("操作開始");
await new Promise(resolve => setTimeout(resolve, 1000));
console.log("操作完了");
} catch (error) {
console.error("エラーが発生しました:", error);
}
}
async function main() {
await 非同期操作();
}
main();
この例では、console.log
を使用して非同期処理の開始と完了をログ情報として記録し、try...catch
ブロックでエラーハンドリングを行っている。さらに、デバッグツール(例えば、Chrome DevToolsやNode.jsのデバッガ)を使用して、非同期コードの実行フローを詳細に追跡することができる。
Pythonでは、asyncio
ライブラリのデバッグモードを有効にすることで、非同期処理のデバッグを支援することができる[1][2]。
import asyncio
import logging
async def 非同期操作():
await asyncio.sleep(1)
raise Exception("エラー発生")
async def main():
try:
await 非同期操作()
except Exception as e:
print(f"エラーが発生しました: {e}")
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
asyncio.run(main())
この例では、logging
ライブラリを使用してデバッグ情報を記録し、非同期処理中のエラーを詳細に追跡している。
これらの技法とツールを使用することで、非同期処理に関連する一般的な問題を効果的に解決し、安定したアプリケーションを構築することができる。
代替手法
[編集]コールバック
[編集]コールバックは、非同期処理の最も基本的な手法の一つである[4][5]。関数が非同期に処理を行い、その処理が完了したときにコールバック関数が呼び出される。コールバックはシンプルで理解しやすいが、複雑な非同期処理を管理する際に「コールバック地獄」と呼ばれるネストが深くなる問題が発生しやすい。以下に、JavaScriptでの例を示す。
function 非同期操作(callback) {
setTimeout(() => {
callback("結果");
}, 1000);
}
function main() {
非同期操作(result => {
console.log("取得した結果:", result);
});
}
main();
この例では、setTimeout
を使用して非同期処理をシミュレートし、処理が完了した際にコールバック関数が呼び出される。
プロミス
[編集]プロミス(Promise)は、非同期処理の完了または失敗を表現するオブジェクトであり、コールバックに比べて可読性と管理のしやすさが向上している[4][5]。プロミスは、then
およびcatch
メソッドを使用して、非同期処理の結果やエラーを処理する。以下に、JavaScriptでの例を示す。
function 非同期操作() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("結果");
}, 1000);
});
}
function main() {
非同期操作()
.then(result => {
console.log("取得した結果:", result);
})
.catch(error => {
console.error("エラーが発生しました:", error);
});
}
main();
この例では、Promise
を使用して非同期処理を管理し、処理が完了した際にthen
メソッドで結果を処理し、エラーが発生した場合にはcatch
メソッドでエラーハンドリングを行っている。
リアクティブプログラミング
[編集]リアクティブプログラミングは、データストリームと変更の伝播を中心としたプログラミングパラダイムであり、非同期処理を効率的に処理するための強力な手法である[40][41]。リアクティブプログラミングは、イベント駆動型プログラムの作成に適しており、ObservableやObserverなどの概念を使用する。以下に、RxJSを使用したJavaScriptの例を示す。
const { of } = require('rxjs');
const { delay } = require('rxjs/operators');
function 非同期操作() {
return of("結果").pipe(delay(1000));
}
function main() {
非同期操作().subscribe(
result => console.log("取得した結果:", result),
error => console.error("エラーが発生しました:", error)
);
}
main();
この例では、RxJSのof
関数を使用してObservableを作成し、delay
オペレーターで非同期処理をシミュレートしている。subscribe
メソッドを使用して、非同期処理の結果を処理し、エラーが発生した場合にはエラーハンドリングを行っている。
リアクティブプログラミングは、非同期データストリームを効率的に管理するための強力なツールであり、特に複雑な非同期処理を簡潔に記述することができる。
これらの代替手法(コールバック、プロミス、リアクティブプログラミング)を理解することで、様々な状況に応じた最適な非同期処理の選択が可能となる。非同期処理の適切な手法を選ぶことにより、コードの可読性と保守性を向上させ、効率的なプログラムを構築することができる。
出典
[編集]- ^ a b c d e f g h i j k l m n o p q r s t u Fowler, Matthew (2022-03-15) (英語). Python Concurrency with asyncio. Simon and Schuster. ISBN 978-1-63835-708-7
- ^ a b c d e f g h i j k l m n o p Bader, Dan (2017) (英語). Python Tricks: The Book. Ron Holland Designs. ISBN 978-1-7750933-0-5
- ^ a b c d e Crockford, Douglas (2008-05-08) (英語). JavaScript: The Good Parts: The Good Parts. "O'Reilly Media, Inc.". ISBN 978-0-596-55487-3
- ^ a b c d e f g h i j k l m n o p q r s t Flanagan, David (2020-05-14) (英語). JavaScript: The Definitive Guide: Master the World's Most-Used Programming Language. "O'Reilly Media, Inc.". ISBN 978-1-4919-5198-9
- ^ a b c d e f g h i j k Haverbeke, Marijn (2018-12-04) (英語). Eloquent JavaScript, 3rd Edition: A Modern Introduction to Programming. No Starch Press. ISBN 978-1-59327-951-6
- ^ a b c d Price, Mark J. (2019-10-31) (英語). C# 8.0 and .NET Core 3.0 – Modern Cross-Platform Development: Build applications with C#, .NET Core, Entity Framework Core, ASP.NET Core, and ML.NET using Visual Studio Code. Packt Publishing Ltd. ISBN 978-1-78847-157-2
- ^ a b c d e f Troelsen, Andrew; Japikse, Philip (2017-11-21) (英語). Pro C# 7: With .NET and .NET Core. Apress. ISBN 978-1-4842-3018-3
- ^ a b Ramalho, Luciano (2015-07-30) (英語). Fluent Python: Clear, Concise, and Effective Programming. "O'Reilly Media, Inc.". ISBN 978-1-4919-4626-8
- ^ Slatkin, Brett (2015-02-12) (英語). Effective Python: 59 Specific Ways to Write Better Python. Addison-Wesley Professional. ISBN 978-0-13-403440-9
- ^ a b Zakas, Nicholas C. (2011-12-20) (英語). Professional JavaScript for Web Developers. John Wiley & Sons. ISBN 978-1-118-23309-2
- ^ Tanenbaum, Andrew S. (1992) (英語). Modern Operating Systems. Prentice Hall. ISBN 978-0-13-588187-3
- ^ Tanenbaum, Andrew S.; Woodhull, Albert S. (2006) (英語). Operating Systems: Design and Implementation. Pearson Prentice Hall. ISBN 978-0-13-142938-3
- ^ Bryant, Randal E.; O'Hallaron, Davie Richard (2016) (英語). Computer Systems: A Programmer's Perspective. Pearson. ISBN 978-0-13-409266-9
- ^ Thomas, David; Hunt, Andrew (2020) (中国語). The pragmatic programmer. qi feng zi xun gu fen you xian gong si. ISBN 978-986-502-275-4
- ^ a b c d e f g h i Skeet, Jon (2019-03-23) (英語). C# in Depth: Fourth Edition. Manning Publications. ISBN 978-1-61729-453-2
- ^ a b c d Greenhalgh, David; Skeen, Josh; Bailey, Andrew (2021-10-05) (英語). Kotlin Programming: The Big Nerd Ranch Guide. Pearson Technology Group. ISBN 978-0-13-687048-7
- ^ a b c d e f g Blandy, Jim; Orendorff, Jason; Tindall, Leonora F. S. (2021-06-11) (英語). Programming Rust. "O'Reilly Media, Inc.". ISBN 978-1-4920-5254-8
- ^ a b “Swiftの新機能 - WWDC21 - ビデオ”. Apple Developer. 2024年7月26日閲覧。
- ^ a b c d Subramaniam, Venkat (2019) (英語). Programming Kotlin: Create Elegant, Expressive, and Performant JVM and Android Applications. Pragmatic Bookshelf. ISBN 978-1-68050-635-8
- ^ a b c d e McNamara, Tim (2021-09-07) (英語). Rust in Action. Simon and Schuster. ISBN 978-1-63835-622-6
- ^ Kerrisk, Michael (2010-10-01) (英語). The Linux Programming Interface: A Linux and UNIX System Programming Handbook. No Starch Press. ISBN 978-1-59327-291-3
- ^ Klemens, Ben (2014-09-27) (英語). 21st Century C: C Tips from the New School. "O'Reilly Media, Inc.". ISBN 978-1-4919-0444-2
- ^ Stevens, W. Richard; Rago, Stephen A. (2013-06-10) (英語). Advanced Programming in the UNIX Environment. Addison-Wesley. ISBN 978-0-321-63800-7
- ^ Levin, Jonathan (2012-11-05) (英語). Mac OS X and iOS Internals: To the Apple's Core. John Wiley & Sons. ISBN 978-1-118-23605-5
- ^ Kcholi, Abraham (2012-02-24) (英語). Pro Windows Embedded Compact 7: Producing Device Drivers. Apress. ISBN 978-1-4302-4180-5
- ^ a b c d Williams, Anthony (2019-02-07) (英語). C++ Concurrency in Action. Simon and Schuster. ISBN 978-1-63835-635-6
- ^ Josuttis, Nicolai M. (2019-09-06) (英語). C++17 - The Complete Guide. Nicojosuttis. ISBN 978-3-96730-917-1
- ^ “Welcome to AIOHTTP — aiohttp 3.9.5 documentation”. docs.aiohttp.org. 2024年7月26日閲覧。
- ^ “Trio: a friendly Python library for async concurrency and I/O — Trio 0.26.0 documentation”. trio.readthedocs.io. 2024年7月26日閲覧。
- ^ a b c Casciaro, Mario; Mammino, Luciano (2020-07-29) (英語). Node.js Design Patterns: Design and implement production-grade Node.js applications using proven patterns and techniques. Packt Publishing Ltd. ISBN 978-1-83921-044-0
- ^ Freeman, Adam (2022-02-25) (英語). Pro ASP.NET Core 6: Develop Cloud-Ready Web Applications Using MVC, Blazor, and Razor Pages. Apress. ISBN 978-1-4842-7956-4
- ^ a b Versluis, Gerald (2017-12-01) (英語). Xamarin.Forms Essentials: First Steps Toward Cross-Platform Mobile Apps. Apress. ISBN 978-1-4842-3240-8
- ^ a b Hocking, Joseph (2022-02-08) (英語). Unity in Action, Third Edition: Multiplatform Game Development in C#. Simon and Schuster. ISBN 978-1-61729-933-9
- ^ a b c Syme, Don; Granicz, Adam; Cisternino, Antonio (2015-12-31) (英語). Expert F# 4.0. Apress. ISBN 978-1-4842-0740-6
- ^ a b Eason, Kit (2018-11-29) (英語). Stylish F#: Crafting Elegant Functional Code for .NET and .NET Core. Apress. ISBN 978-1-4842-4000-7
- ^ Horton, John (2019-04-30) (英語). Android Programming with Kotlin for Beginners: Build Android apps starting from zero programming experience with the new Kotlin programming language. Packt Publishing Ltd. ISBN 978-1-78980-088-3
- ^ Todorov, Marin; Team, Kodeco (2023-02-14) (英語). Modern Concurrency in Swift (Second Edition): Introducing Async/Await, Task Groups & Actors. Amazon Digital Services LLC - Kdp. ISBN 978-1-950325-81-8
- ^ Kautsch, Andrés Ibañez (2022-11-15) (英語). Modern Concurrency on Apple Platforms: Using async/await with Swift. Apress. ISBN 978-1-4842-8694-4
- ^ a b Cleary, Stephen (2014-05-15) (英語). Concurrency in C# Cookbook: Asynchronous, Parallel, and Multithreaded Programming. "O'Reilly Media, Inc.". ISBN 978-1-4919-0668-2
- ^ Mansilla, Sergi (2018-02-05) (英語). Reactive Programming with RxJS 5: Untangle Your Asynchronous JavaScript Code. Pragmatic Bookshelf. ISBN 978-1-68050-553-5
- ^ Oliveira, Erich de Souza (2017-05-26) (英語). Mastering Reactive JavaScript. Packt Publishing Ltd. ISBN 978-1-78646-346-3