同時実行オプション
Effect は、エフェクトがどのように実行されるかを管理し、全体の操作の結果を制御するためのさまざまなオプションを提供します。これらのオプションは、同時に実行できるエフェクトの数を決定するのに役立ちます。
type Options = { readonly concurrency?: Concurrency; /* ... その他のオプション ... */};このセクションでは、同時実行を管理するオプション、すなわちconcurrencyオプションに焦点を当てます。このオプションは、Concurrency型を持ちます。
type Concurrency = number | "unbounded" | "inherit";各設定値の意味を理解しましょう。
以下の例ではEffect.all関数を使用していますが、この概念はEffect.forEachなど、同時実行オプションを受け入れる他の多くの Effect
API にも適用されます。
順次実行(デフォルト)
デフォルトでは、同時実行オプションを指定しない場合、エフェクトは順次実行されます。これは、各エフェクトが前のエフェクトが完了した後にのみ開始されることを意味します。
import { Effect, Duration } from "effect";
const makeTask = (n: number, delay: Duration.DurationInput) => Effect.promise( () => new Promise<void>((resolve) => { console.log(`task${n}を開始`); setTimeout(() => { console.log(`task${n}が完了`); resolve(); }, Duration.toMillis(delay)); }) );
const task1 = makeTask(1, "200 millis");const task2 = makeTask(2, "100 millis");
const sequential = Effect.all([task1, task2]);
Effect.runPromise(sequential);/*出力:task1を開始task1が完了task2を開始 <-- task2はtask1が完了した後に開始されますtask2が完了*/数値による同時実行
concurrencyオプションを使用することで、同時に実行する操作の数を制御できます。たとえば、concurrency: 2を指定することで、最大 2 つのエフェクトが同時に実行されます。
import { Effect, Duration } from "effect";
const makeTask = (n: number, delay: Duration.DurationInput) => Effect.promise( () => new Promise<void>((resolve) => { console.log(`task${n}を開始`); setTimeout(() => { console.log(`task${n}が完了`); resolve(); }, Duration.toMillis(delay)); }) );
const task1 = makeTask(1, "200 millis");const task2 = makeTask(2, "100 millis");const task3 = makeTask(3, "210 millis");const task4 = makeTask(4, "110 millis");const task5 = makeTask(5, "150 millis");
const number = Effect.all([task1, task2, task3, task4, task5], { concurrency: 2,});
Effect.runPromise(number);/*出力:task1を開始task2を開始 <-- アクティブなタスク: task1, task2task2が完了task3を開始 <-- アクティブなタスク: task1, task3task1が完了task4を開始 <-- アクティブなタスク: task3, task4task4が完了task5を開始 <-- アクティブなタスク: task3, task5task3が完了task5が完了*/無制限の同時実行
concurrency: "unbounded"を設定すると、必要に応じてできるだけ多くのエフェクトが同時に実行されます。特定の制限はありません。
import { Effect, Duration } from "effect";
const makeTask = (n: number, delay: Duration.DurationInput) => Effect.promise( () => new Promise<void>((resolve) => { console.log(`task${n}を開始`); setTimeout(() => { console.log(`task${n}が完了`); resolve(); }, Duration.toMillis(delay)); }) );
const task1 = makeTask(1, "200 millis");const task2 = makeTask(2, "100 millis");const task3 = makeTask(3, "210 millis");const task4 = makeTask(4, "110 millis");const task5 = makeTask(5, "150 millis");
const unbounded = Effect.all([task1, task2, task3, task4, task5], { concurrency: "unbounded",});
Effect.runPromise(unbounded);/*出力:task1を開始task2を開始task3を開始task4を開始task5を開始task2が完了task4が完了task5が完了task1が完了task3が完了*/親継承同時実行
concurrency: "inherit"オプションは、Effect.withConcurrency(number | "unbounded")によって制御されるコンテキストに基づいて適応します。
Effect.withConcurrency呼び出しがない場合、デフォルトは"unbounded"です。それ以外の場合、Effect.withConcurrencyによって設定された構成を継承します。
import { Effect, Duration } from "effect";
const makeTask = (n: number, delay: Duration.DurationInput) => Effect.promise( () => new Promise<void>((resolve) => { console.log(`task${n}を開始`); setTimeout(() => { console.log(`task${n}が完了`); resolve(); }, Duration.toMillis(delay)); }) );
const task1 = makeTask(1, "200 millis");const task2 = makeTask(2, "100 millis");const task3 = makeTask(3, "210 millis");const task4 = makeTask(4, "110 millis");const task5 = makeTask(5, "150 millis");
const inherit = Effect.all([task1, task2, task3, task4, task5], { concurrency: "inherit",});
Effect.runPromise(inherit);/*出力:task1を開始task2を開始task3を開始task4を開始task5を開始task2が完了task4が完了task5が完了task1が完了task3が完了*/Effect.withConcurrencyを使用すると、その特定の同時実行設定を採用します。
import { Effect, Duration } from "effect";
const makeTask = (n: number, delay: Duration.DurationInput) => Effect.promise( () => new Promise<void>((resolve) => { console.log(`task${n}を開始`); setTimeout(() => { console.log(`task${n}が完了`); resolve(); }, Duration.toMillis(delay)); }) );
const task1 = makeTask(1, "200 millis");const task2 = makeTask(2, "100 millis");const task3 = makeTask(3, "210 millis");const task4 = makeTask(4, "110 millis");const task5 = makeTask(5, "150 millis");
const inherit = Effect.all([task1, task2, task3, task4, task5], { concurrency: "inherit",});
const withConcurrency = inherit.pipe(Effect.withConcurrency(2));
Effect.runPromise(withConcurrency);/*出力:task1を開始task2を開始 <-- アクティブなタスク: task1, task2task2が完了task3を開始 <-- アクティブなタスク: task1, task3task1が完了task4を開始 <-- アクティブなタスク: task3, task4task4が完了task5を開始 <-- アクティブなタスク: task3, task5task3が完了task5が完了*/