0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ninda 6日目: 非同期プログラミング 〜async/awaitとninda〜

Posted at

今日のゴール

  • Nimの非同期プログラミングの基礎を理解する
  • nindaの非同期APIを効果的に使う
  • 並行処理のパターンを実装する

なぜ非同期が重要か

タプルスペースは複数のプロセスが協調する仕組みです。効率的な協調には非同期処理が欠かせません。

同期処理では待機時間が無駄になりますが、非同期処理では複数のWorkerが並行して動作します。


Nimのasync/await

基本構文

import std/asyncdispatch

# 非同期関数の定義
proc fetchData(): Future[string] {.async.} =
  await sleepAsync(100)  # 非同期で待機
  return "data"

# イベントループの実行
waitFor main()

Future[T]型

Future[T]は「いずれT型の値が得られる」という約束を表します。

状態 説明
未完了 処理中、まだ値がない
完了 値が準備できた
失敗 例外が発生した

nindaの非同期API

すべての操作に非同期版(*Async)があります。

操作 同期版 非同期版
書き込み write() writeAsync()
読み取り read() readAsync()
取り出し take() takeAsync()
非ブロッキング tryRead() tryReadAsync()
全件取得 readAll() readAllAsync()
# 基本的な使い方
await ts.writeAsync(toTuple(strVal("task"), intVal(1)))
let result = await ts.readAsync(pattern)
let taken = await ts.takeAsync(pattern)

asyncCheckとawaitの違い

await: 完了を待つ

await task1()  # task1が完了するまで待つ
await task2()  # task1完了後にtask2を実行

asyncCheck: 投げっぱなし

asyncCheck task1()  # task1を開始して即座に次へ
asyncCheck task2()  # task2も開始
# task1とtask2は並行実行される

使い分けの図解


並行処理パターン

パターン1: 並行ワーカー

proc worker(id: int) {.async.} =
  while true:
    let task = await ts.tryTakeAsync(taskPattern)
    if task.isSome:
      echo "Worker ", id, ": Processing"
      await sleepAsync(100)

# 3つのワーカーを並行起動
asyncCheck worker(1)
asyncCheck worker(2)
asyncCheck worker(3)

パターン2: 待ち合わせ(Rendezvous)

2つのプロセスが互いを待ち合わせるパターン。

proc processA() {.async.} =
  await ts.writeAsync(toTuple(strVal("sync"), strVal("A_ready")))
  discard await ts.takeAsync(toPattern(strVal("sync"), strVal("B_ready")))
  echo "A: Both ready!"

まとめ

学んだこと

トピック ポイント
async/await Nimの非同期プログラミングの基礎
Future[T] 将来の値を表す型
非同期API *Async サフィックスの操作
await vs asyncCheck 逐次 vs 並行

いつ使うか

場面 推奨
結果が必要 await
バックグラウンド処理 asyncCheck
複数ワーカー起動 asyncCheck

演習問題

問題6-1: 並行カウンター

3つのプロセスが並行してカウンターをインクリメントするプログラムを作成してください。

ヒント
  • カウンターは("counter", 値)というタプルで表現
  • インクリメント = take → 値+1 → write
  • 最終的な値は予測可能か?(タプルスペースの操作は原子的であることを思い出そう)

問題6-2: パイプライン

3段階のパイプライン(入力→変換→出力)を非同期で実装してください。

ヒント
  • 3つのスペース: input, transform, output
  • 各段階は独立したasyncプロセス
  • 入力プロセス: 数値をinputスペースに書き込む
  • 変換プロセス: inputから取り出し、2倍にしてtransform
  • 出力プロセス: transformから取り出して表示

問題6-3: タイムアウト付き待機

最大5秒間タスクを待ち、タイムアウトしたら諦めるワーカーを実装してください。

ヒント
  • readAsync(pattern, timeout = 5000)を使用
  • TimeoutError例外をキャッチ
  • Day 8で詳しく学びます

前回: パターンマッチング | 目次 | 次回: 名前付きスペース

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?