async/await 比較（C#, JavaScript, Python）

## メッセージループ

### C#

Dispatcher.Run()

```C#
using System.Windows.Threading;

Dispatcher.CurrentDispatcher.InvokeAsync(async () =>
{
   // いろいろな処理...

   // メッセージループを終了させる
   Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Normal);
});

Dispatcher.Run();
```

WPF とか WinForms とかでは、フレームワークがすでにメッセージループを回しているので、自分で Dispatcher.Run() する必要はない。

### JavaScript

自分で書く必要なし。

### Python

asyncio.run(最初に実行するasync関数)

```python
import asyncio

async def main():
    # いろいろな処理...
    pass

asyncio.run(main())
```

## await で待つ sleep

実用的に使うことは少ないけど、実験ではよく使用するので...

### C#

```C#
await Task.Delay(1500); // 単位はミリ秒
```

### JavaScript

ない... ので、自分で作る。

```JavaScript
function sleepAsync(t) {
    return new Promise(resolve => setTimeout(resolve, t));
}
// 使い方
await sleepAsync(1500); // 単位はミリ秒
```

### Python

```python
import asyncio
await asyncio.sleep(1.5) # 単位は秒
```

## 普通の sleep

通常、使わない。けど、実験ではよく使うので...

### C#

```C#
System.Threading.Thread.Sleep(1500); // 単位はミリ秒
```

### JavaScript

ない。ので、無理やり作る。
※ 他の言語での組み込み sleep と違って、これは、CPUリソースを消費する

```javascript
function sleep(t) {
  const startTime = (new Date()).getTime();
  while ((new Date()).getTime() - startTime < t) {}
}
// 使い方
sleep(1500); // 単位はミリ秒
```

### Python

```python
import time
time.sleep(1.5) # 単位は秒
```

## async な関数（中で await が使用可能な関数）の定義

### C#

戻り値がある場合は、「async Task<戻り値の型> FooAsync() { ... }」
戻り値がない場合は、「async Task FooAsync() { ... }」
※ 「async void FooAsync() {...}」でもOKだけど、await できない関数になる

ラムダ式は「async () => ...」

```C#
async Task<int> FooAsync()
{
    int ret1 = await FooAsync1();
    int ret2 = await FooAsync2();
    return ret1 + ret2;
}
// 使うときはこんな感じ
int val = await FooAsync();
```

### JavaScript

「async function fooAsync() { ... }」
ラムダ式は「async () => ...」

```javascript
async function fooAsync() {
    const ret1 = await fooAsync1();
    const ret2 = await fooAsync2();
    return ret1 + ret2;
}
// 使うときはこんな感じ
let val = await fooAsync();
```

### Python

「async def fooAsync(): ...」
ラムダ式で async は、Python にはない。
```python
async def fooAsync():
    ret1 = await fooAsync1()
    ret2 = await fooAsync2()
    return ret1 + ret2

# 使うときはこんな感じ
val = await fooAsync()
```

## async な関数の実行

### C#

実行を開始して終わるまで待つ場合は、「await FooAsync()」

終わるのを待たずに実行する場合は、普通に関数を実行する。
後で、終わるまで待ちたい場合は、戻り値を取っておいて、後でそれを await する。
```C#
var task1 = FooAsync1(); // FooAsync1 を実行
var task2 = FooAsync2(); // FooAsync1 の実行が終わる前に FooAsync2 が実行が開始される
await task1; // FooAsync1 の実行が終わるまで待つ
await task2; // FooAsync2 の実行が終わるまで待つ
```

### JavaScript

C# と同じ。
```JavaScript
const task1 = fooAsync1(); // fooAsync1 を実行
const task2 = fooAsync2(); // fooAsync1 の実行が終わる前に fooAsync2 が実行が開始される
await task1; // fooAsync1 の実行が終わるまで待つ
await task2; // fooAsync2 の実行が終わるまで待つ
```

### Python

実行を開始して終わるまで待つ場合は、他と同様「await fooAsync()」

終わるのを待たずに実行する場合は、「asyncio.create_task(fooAsync())」
```python
task1 = asyncio.create_task(fooAsync1()) # fooAsync1 を実行
task2 = asyncio.create_task(fooAsync2()) # fooAsync1 の実行が終わる前に fooAsync2 が実行が開始される
await task1 # fooAsync1 の実行が終わるまで待つ
await task2 # fooAsync2 の実行が終わるまで待つ
```

Python の場合、async な関数は呼び出しただけでは、実行が開始されない。
await するとか、asyncio.create_task() とかした時点で実行が開始される。
（なので、上記の例を C#, JavaScript と同じように書くと、fooAsync1, fooAsync2 は、並列に実行されず、順番に実行される）

実行されることなく、戻り値のオブジェクトが解放されると
「RuntimeWarning: coroutine 'xxx' was never awaited」
のようなメッセージが出る。

## コールバックを async, await で扱えるようにする

### C#

System.Threading.Tasks.TaskCompletionSource<T> を利用。

```C#
Task<Info> GetCallbackedInfoAsync(SomeCalculator calculator)
{
    var tcs = new TaskCompletionSource<Info>();
    // Calc メソッドは、何か計算して結果をコールバックで通知する
    calculator.Calc(info => tcs.SetResult(info));
    return tcs.Task;
}

// 使うときはこんな感じ
var calculator = new SomeCalculator();
Info info = await GetCallbackedInfoAsync(calculator);
```

### JavaScript

Promise を利用。

```javascript
function getCallbackedInfoAsync(calculator) {
    return new Promise(resolve => {
        calculator.calc(info => resolve(info));
    });
}
// 使うときはこんな感じ
const calculator = new SomeCalculator();
const info = await getCallbackedInfoAsync(calculator);
```

### Python

asyncio.Future を利用。

```python
import asyncio

def getCallbackedInfoAsync(calculator: SomeCalculator):
    future = asyncio.Future()
    def callbackFunc(info):
        future.set_result(info)
    # calc メソッドは、何か計算して結果をコールバックで通知する
    calculator.calc(callbackFunc)
    return future

# callback が別スレッドで呼び出される場合...
def getCallbackedInfoAsync2(calculator: SomeCalculator):
    msgLoop = asyncio.get_running_loop()
    future = asyncio.Future()
    def callbackFunc(info):
        # asyncio.Future はスレッドセーフじゃないので、呼び出し元のスレッド上で結果をセットする
        msgLoop.call_soon_threadsafe(future.set_result, info)
    # calc メソッドは、何か計算して結果をコールバックで通知する
    calculator.calc(callbackFunc)
    return future


# 使うときはこんな感じ
calculator = SomeCalculator()
info = await getCallbackedInfoAsync(calculator)
```

## generator

### C# (ver. 8 以降)

```C#
// generator の作成
async IAsyncEnumerable<int> CountAsync(int n)
{
    for (int i = 0; i < n; i++)
    {
        await Task.Delay(500);
        yield return i;
    }
}
// 使うときはこんな感じ
async Task TestAsync()
{
    await foreach (var n in Count(5))
    {
        Console.WriteLine(n);
    }
});
```

### JavaScript

```javascript
function sleepAsync(t) { return new Promise(resolve => setTimeout(resolve, t)); }

// generator の作成
async function* countAsync(n) {
    for (let i = 0; i < n; i++) {
        await sleepAsync(500);
        yield i;
    }
}
// 使うときはこんな感じ
async function testAsync() {
    for await (const n of countAsync(5)) {
        console.log(n);
    }
}
```

### Python

```python
# generator の作成
async def countAsync(n):
    for i in range(n):
        await asyncio.sleep(0.5)
        yield i

# 使うときはこんな感じ
async def testAsync():
    async for i in countAsync(5):
        print(i)
```

## 別スレッドで実行して、await で終わるまで待つ

### C#

```C#
await Task.Run(() =>
{
    // この部分が別スレッドで実行される
});
// 別スレッドでの実行が終わると、ここに到達する
```

### Python

※ Python 3.9 以降

```Python
def someFunc():
    # この部分が別スレッドで実行される
    ...

await asyncio.to_thread(someFunc)
```

## ワーカースレッド（メッセージループを持つスレッド）を作る

### C#

```C#
// ワーカースレッドを作成して、その Dispatcher を返す
System.Windows.Threading.Dispatcher CreateWorkerThread()
{
    var tcs = new TaskCompletionSource<System.Windows.Threading.Dispatcher>();
    var thread = new Thread(() =>
    {
        tcs.SetResult(System.Windows.Threading.Dispatcher.CurrentDispatcher);
        System.Windows.Threading.Dispatcher.Run();
    });
    thread.Start();
    return tcs.Task.Result;
}
// 使う時はこんな感じ...
var workerDispatcher = CreateWorkerThread();
// ワーカースレッド上で実行させる
await workerDispatcher.InvokeAsync(() =>
{
    // この部分がワーカースレッド上で実行される
});
// ワーカースレッドを終了させる
workerDispatcher.BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.Normal);
```

### JavaScript

```worker.js
self.addEventListener('message', e => {
    // main.js で postMessage されたときに、この部分がワーカースレッド上で実行される
    const calcResult = e.data * e.data;
    self.postMessage(calcResult);
});
```

```main.js
const worker = new Worker('worker.js');
worker.addEventListener("message", e => {
    console.log(e.data);
});
worker.postMessage(3);
```


### Python

```python
import asyncio
import threading
import concurrent.futures
import time

# ワーカースレッドを作成して、そのメッセージループを返す
def createWorkerThread() -> asyncio.AbstractEventLoop:
    future = concurrent.futures.Future()
    def workerThreadMain():
        msgLoop = asyncio.new_event_loop()
        asyncio.set_event_loop(msgLoop)
        future.set_result(msgLoop)
        msgLoop.run_forever()

    thread = threading.Thread(target=workerThreadMain)
    thread.start()
    return future.result()

# 使うときは、こんな感じ...

async def main():
    mainMsgLoop = asyncio.get_running_loop()
    workerMsgLoop = createWorkerThread()
    for i in range(5):
        # ワーカースレッド上で testFunc を実行させる
        f = asyncio.Future()  # 結果を待つための Future
        workerMsgLoop.call_soon_threadsafe(testFunc, mainMsgLoop, f, i)
        val = await f # 結果を取得
        print(f"result={val}")
    # ワーカースレッドを停止
    workerMsgLoop.call_soon_threadsafe(lambda: workerMsgLoop.stop())

# 1秒かけて、与えられた数の2乗を計算
def testFunc(msgLoop: asyncio.AbstractEventLoop, future : asyncio.Future, i):
    time.sleep(1)
    calcResult = i * i
    msgLoop.call_soon_threadsafe(lambda: future.set_result(calcResult))

asyncio.run(main())
print("main done")
```

## インタラクティブ環境

### C#

- VisualStudio 2022 の C#インタラクティブ
    - await は、利用可能
    - async 関数を await なしで実行すると、ちゃんとバックグラウンドで実行される
- その他、コンソール上のインタラクティブ環境
    - メッセージループが実行されていない
        (await は、動作するが、マルチスレッドになる)

### JavaScript

- ブラウザのデバッグコンソール
    - await は、利用可能
    - async 関数を await なしで実行すると、ちゃんとバックグラウンドで実行される

### Python

- ipython
    - await は、利用可能
    - asyncio.create_task(...) は、エラーになる
- Jupyer Notebook
    - await は、利用可能
    - asyncio.create_task(...) も OK (ちゃんとバックグラウンドで実行される)
    - バックグラウンドで実行されたものの標準出力は、直近に実行した出力結果のところに表示される

## その他...

### C# で、メッセージループがないとき

Python では、メッセージループが起動していないときは、async, await を使用するとエラーになる。
JavaScript は、そもそも、メッセージループが起動していない、という状況は存在しない。
でも、C# ではエラーにならず、動作する。

ただ...  メッセージループの有無で結構挙動が異なる。
以下のようなプログラムで違いを見てみる。

```C#
async Task Test()
{
    Console.WriteLine($"Start TID={Thread.CurrentThread.ManagedThreadId}");
    var task1 = Foo("A");
    var task2 = Foo("B");
    await task1;
    Console.WriteLine($"task1 done TID={Thread.CurrentThread.ManagedThreadId}");
    await task2;
    Console.WriteLine($"task2 done TID={Thread.CurrentThread.ManagedThreadId}");
}
async Task Foo(string tag)
{
    Console.WriteLine($"{tag}: TID={Thread.CurrentThread.ManagedThreadId}");
    for (int i = 0; i < 3; i++)
    {
        await Task.Delay(100);
        Console.WriteLine($"{tag}: Before sleep TID={Thread.CurrentThread.ManagedThreadId}");
        Thread.Sleep(200);
        Console.WriteLine($"{tag}: After  sleep TID={Thread.CurrentThread.ManagedThreadId}");
    }
}
```

メッセージループがある状態とない状態で、それぞれ Test() を実行した場合、以下のようになる。
<table>
<tr>
<th>メッセージループあり</th>
<th>メッセージループなし</th>
</tr>
<tr>
<td>
Start TID=1<br>
A: TID=1<br>
B: TID=1<br>
B: Before sleep TID=1<br>
B: After  sleep TID=1<br>
A: Before sleep TID=1<br>
A: After  sleep TID=1<br>
B: Before sleep TID=1<br>
B: After  sleep TID=1<br>
A: Before sleep TID=1<br>
A: After  sleep TID=1<br>
B: Before sleep TID=1<br>
B: After  sleep TID=1<br>
A: Before sleep TID=1<br>
A: After  sleep TID=1<br>
task1 done TID=1<br>
task2 done TID=1<br>
</td>
<td>
Start TID=1<br>
A: TID=1<br>
B: TID=1<br>
B: Before sleep TID=4<br>
A: Before sleep TID=5<br>
B: After  sleep TID=4<br>
A: After  sleep TID=5<br>
A: Before sleep TID=4<br>
B: Before sleep TID=6<br>
B: After  sleep TID=6<br>
A: After  sleep TID=4<br>
A: Before sleep TID=5<br>
B: Before sleep TID=6<br>
A: After  sleep TID=5<br>
B: After  sleep TID=6<br>
task1 done TID=5<br>
task2 done TID=5
</td>
</table>

メッセージループがない場合、A と B が異なるスレッドで動作するため、Thred.Sleep(200) が同時に動いてしまう。

### Python の async with

```python
    async with foo() as obj:
        いろいろな処理
```

これは、以下とほぼ同等
（例外発生時に \_\_aexit__ に例外情報が与えられる）
```python
    obj = foo()
    await obj.__aenter__()
    try:
        いろいろな処理
    finally:
        await obj.__aexit__(None, None, None)
```