---
title: "VOICEVOXをApple containerで動かしたらCPUが4コアしか使われていなかったので割り当てを増やした"
description: "Mac で常駐の VOICEVOX サーバーを Apple container で動かしたら、デフォルトでコンテナに 4 CPU しか割り当てられず、合成速度を本来の 4.5 分の 1 に落としていました。M5 Max での実測を交えて、cpus と cpu_num_threads を両方詰める設定を紹介します。"
category: "DevOps"
tags: ["VOICEVOX","Apple Container","macOS","Apple Silicon","TTS","Performance"]
publishedAt: "2026-07-07"
lastmod: "2026-08-06"
---

技術ニュースを RSS → Gemini で要約して Podcast 化する個人パイプラインで、TTS を Gemini TTS から VOICEVOX に置き換えられないか検討していました。常駐エンジンとして VOICEVOX を Mac で動かすにあたって、Apple 純正の [container CLI](https://github.com/apple/container) を使ったところ、合成速度が明らかに遅い現象に遭遇しました。原因はコンテナ側のデフォルト CPU 割り当てで、`container run` のオプション 2 つを足すだけで合成速度がほぼ 4.5 倍になります。

::card[https://github.com/apple/container]

本記事は Docker Desktop ではなく、GitHub で配布されている Apple 純正の `container` コマンド(macOS 26 が必要、執筆時点 v1.0.0)に固有の落とし穴の話です。Docker Desktop はデフォルトで host の全コアが割り当てられるので踏まないはずです。

## まずは素直に立てる

VOICEVOX 公式の Docker イメージは `voicevox/voicevox_engine:cpu-latest` が arm64 にも対応しているので、Apple container でも `container run` で素直に動きます。

```bash
container run --rm \
  -p 127.0.0.1:50021:50021 \
  voicevox/voicevox_engine:cpu-latest
```

起動したら HTTP API で生存確認します。VOICEVOX engine は `:50021` にいて、`/version` が pong 代わりに使えます。

```python
import urllib.request
with urllib.request.urlopen("http://127.0.0.1:50021/version") as r:
    print(r.read().decode())
# => "0.25.2"
```

ここまでは何の問題もなく動きます。

## ベンチを取ったら明らかに遅い

VOICEVOX のコミュニティに [KuronekoServer/voicevox_bench](https://github.com/KuronekoServer/voicevox_bench) という測定スクリプトがあります。`/synthesis` を 10/50/100 文字 × 10 回計測する素直な測定スクリプトで、[zenn の比較表](https://zenn.dev/kuronekoserver/articles/d63fc8c71c44e3) の元データもこれです。

同じ手法をそのまま M5 Max(18 コア、6 Super コア + 12 Performance コア)の Apple container 上で叩いてみたところ、次のような数字が返ってきました。

| 文字数 | mean |
|---|---|
| 10 | 0.82 s |
| 50 | 2.73 s |
| 100 | 5.19 s |
| Avg | 2.92 s |

zenn の表で並んでいる NVIDIA / AMD / Intel GPU と比較すると、100 文字あたり RTX 4090(0.0964 s)の **約 54 倍遅い**水準で、ノート向け Radeon 780M(0.8332 s)にすら届いていません。一方で voicevox_core を Rust から直叩きしたときには、同じ M5 Max で 113 文字を 1.48 秒(RTF 0.069)で生成できていました。

HTTP オーバーヘッドだけでこの差は出ません。何かをコンテナに取られている前提で `container inspect` を見にいきました。

## Apple container は**デフォルトで 4 CPU しか割り当てない**

`container ls -q | head -1 | xargs container inspect` を見ると、resources セクションが次のようになっていました。

```json
"resources" : {
  "cpuOverhead" : 1,
  "cpus" : 4,
  "memoryInBytes" : 1073741824
}
```

ホストが 18 コアあろうと、Apple container は**コンテナに 4 CPU・1 GB メモリを固定で割り当てる**のがデフォルトです。[公式ドキュメント](https://github.com/apple/container/blob/main/docs/how-to.md)にもこの値は明記されていますが、`container run --help` や `-c, --cpus` / `-m, --memory` のリファレンスには出てこないので、素直に立てると見落としやすい設定です。

```text
-c, --cpus <cpus>       Number of CPUs to allocate to the container
-m, --memory <memory>   Amount of memory (1MiByte granularity), with optional unit
```

VOICEVOX engine 側はこれと別に `cpu_num_threads` という設定を持っていて、物理コア数と論理コア数が一致する環境(Apple Silicon はこれに該当します)では、未指定だと**論理コア数の半分**で動きます([Issue #1092](https://github.com/VOICEVOX/voicevox_engine/issues/1092) で提案された実装です)。コンテナ側が 4 CPU、engine 側が「その半分」つまり**2 スレッド**しか使えていない状態だった、というのが今回の実態でした。

![ホストのM5 Maxは18コアあるが、Apple containerはコンテナへ既定で4 CPUしか割り当てず、ホストの18コアはコンテナから見えない。さらにVOICEVOX engineは未指定だと論理コア数の半分で動くため、見えている4のさらに半分の2スレッドしか使わない](/images/posts/voicevox-apple-container-cpu-allocation/double-narrowing.svg)

## まずは `-c` と `-m` を渡す

最初にやるのは `container run` 側でリソースを明示することです。M5 Max なら全コア渡してしまって構いません。

```bash
container run --rm \
  -c 18 -m 8g \
  -p 127.0.0.1:50021:50021 \
  voicevox/voicevox_engine:cpu-latest
```

これだけで `container inspect` の resources が `cpus: 18, memory: 8192 MiB` になります。同じベンチを取り直すと、Avg ベースで 2.92 s → 0.87 s と**3.4 倍速く**なりました。コンテナに 18 CPU 見えていれば、engine デフォルトの「半分」も 9 スレッドまで使える計算で、ほぼそのまま線形に効きます。

| 設定 | 100 char | Avg |
|---|---|---|
| デフォルト(`cpus: 4`) | 5.19 s | 2.92 s |
| `-c 18 -m 8g`(threads default = 9) | 1.54 s | 0.87 s |

## さらに `VV_CPU_NUM_THREADS` で詰める

engine 側のデフォルト「半分」を上書きして、全 18 スレッドを使わせます。VOICEVOX engine は `--cpu_num_threads` または環境変数 `VV_CPU_NUM_THREADS` を見るので、後者を渡すのが Apple container では楽です。

```bash
container run --rm \
  -c 18 -m 8g \
  -p 127.0.0.1:50021:50021 \
  -e VV_CPU_NUM_THREADS=18 \
  voicevox/voicevox_engine:cpu-latest
```

`container inspect` の `initProcess.environment` に `VV_CPU_NUM_THREADS=18` が乗ったら、engine 側は 18 スレッドで動きます。ベンチ再計測の結果がこれです。

| 設定 | 10 char | 50 char | 100 char | Avg |
|---|---|---|---|---|
| デフォルト(`cpus: 4`) | 0.82 | 2.73 | 5.19 | 2.92 |
| `-c 18 -m 8g`(threads default) | 0.26 | 0.81 | 1.54 | 0.87 |
| `-c 18 -m 8g` + `threads=18` | 0.22 | 0.60 | 1.11 | 0.64 |

最終的に**デフォルトの 4.5 倍速く**なりました。

## VOICEVOX 公式の「半分で頭打ち」前提は M シリーズに当てはまらない

[Issue #291](https://github.com/VOICEVOX/voicevox_engine/issues/291) では、スレッド数を増やしても性能が伸びない(むしろ落ちる)現象が報告されています。[Issue #1092](https://github.com/VOICEVOX/voicevox_engine/issues/1092) は、その対策としてデフォルト値を論理コア数の半分にする実装を提案したもので、cpu_num_threads のデフォルトの根拠はこちらにあります。これは Intel/AMD のハイブリッドコア(P + E)構成や SMT 込みの環境では妥当な近似ですが、Apple Silicon は別物です。

参考までに M5 Max で `cpu_num_threads` を振ったときの実測(voicevox_core を Rust 直叩きで、113 文字テキスト、release ビルド、warm-up 後 5 回平均、HTTP オーバーヘッドなし)はこうなりました。

| cpu_num_threads | mean | RTF | vs default(9) |
|---|---|---|---|
| 1 | 12.44 s | 0.579 | 0.16× |
| 6(Super のみ) | 2.80 s | 0.130 | 0.72× |
| 0(default ≈ 半分) | 2.01 s | 0.093 | 1.0× |
| 12(Performance のみ) | 1.70 s | 0.079 | 1.18× |
| 18(全コア) | 1.48 s | 0.0687 | 1.36× |

「半分で頭打ち」どころか、**全コア使ったほうが 36 % 速い**結果です。M5 Max は Super コアと Performance コアが混在していますが、`cpu_num_threads=6`(Super コア数に相当)はむしろデフォルトより遅く、`12`(Performance コア数に相当)でデフォルト超え、`18`(全コア)が最速という素直なスケールが出ました。Apple Silicon の Super/Performance 構成は Intel ハイブリッドと違って、Super コア側も合成計算に十分使えるため、半分で頭打ちにする必要がありません。

Rust 直叩き(113 文字、RTF 0.069)を zenn 表の 100 文字実測(秒)と並べると、L4 Tensor(0.134 s)、RTX 4070(0.1102 s)、RX 9070 XT(0.1514 s)より小さい数値です。文字数と指標(RTF と秒)が異なる単純比較にはなりますが、デスクトップ GPU を CPU だけで叩いている水準にあります。

| Device | 100 文字 | 備考 |
|---|---|---|
| RTX 4090 CUDA | 0.0964 s | デスクトップ GPU 最高峰 |
| M5 Max Rust 直叩き(18 threads, 113 文字, RTF) | 0.069 | CPU only |
| RTX 4070 CUDA | 0.1102 s | デスクトップ |
| L4 Tensor CUDA | 0.134 s | データセンター |
| Radeon RX 9070 XT DML | 0.1514 s | デスクトップ |
| Radeon 780M DML(ノート) | 0.8332 s | ノート GPU |
| Intel Arc B580 DML | 1.1474 s | デスクトップ低位 |

Apple container 経由の HTTP API でも、`-c 18 -m 8g + threads=18` で Avg 0.64 s まで縮むので、Intel Arc B580 や Radeon 780M クラスは超えます。10 分の Podcast 音声を 35〜45 秒で生成できる計算で、個人用途では CPU だけで十分な水準でした。

## 未リリースの container 次世代版に期待

Apple container は今年(2026)に [v1.0.0 がリリースされた](https://github.com/apple/container/releases)ばかりで、WWDC 2026 で発表された [Container Machine](https://github.com/apple/container/blob/main/docs/container-machine.md) で systemd 込みの「ちゃんとした Linux 環境」も入ってきています。デフォルトリソース割り当ての挙動が今後のバージョンで Docker Desktop に近づくかどうかは今のところ分かりませんが、root セッション以外のセッションごとにリソースを分ける設計が入ってくる余地はあります。

それまでは、Apple container で何か CPU バウンドなコンテナを動かすときは、まず `container inspect` で `cpus` が幾つになっているか確認するのが定石になりそうです。VOICEVOX に限らず、ffmpeg や ML 系を Apple container で常駐させる人は同じ罠を踏むはずです。