GitHub Actions の新機能 parallel を測ってみたら 7% しか速くならなかった話


GitHub Actions に追加された parallel を matrix / multi-job / sequential(素直に直列) と合わせて 4 パターン、N=10 で計測してみました。
結果、parallel の高速化は sequential 比で 7% にとどまり、並列にした test はむしろ直列で走らせたときより 8 秒遅くなっていました。
内訳を見ると、vitest はもともと自前で並列に走っていて、parallel は CPU の取り合いを増やしただけのようでした。

この記事は、その計測の経緯と結果をまとめたものです。
もともとプロジェクトの中で GitHub Actions の高速化を検討する機会があり、matrix にするか job 分割にするか悩んでいたところに parallel の追加を知り、いい機会だと思って並列実行にかかる時間とコストを簡易的に測ってみました。

並列実行の種類

GitHub Actions で複数のタスクを並列に走らせる方法は、大きく分けて次の 3 つです。

matrix

strategy.matrix で 1 つの job を複数の組み合わせに展開する方法です。

https://docs.github.com/ja/actions/how-tos/write-workflows/choose-what-workflows-do/run-job-variations

公式ドキュメントでは、複数の言語バージョンや複数 OS でテストするといった「同じことを違う条件でやる」使い方が例として挙げられていますが、独立タスクの並列化にも使えます。
job が組み合わせの数だけ立つので、それぞれ別の runner で走ります。

multi-job

独立した job を並べて needs で繋がないやり方です。
matrix と同じく別 runner で走りますが、job ごとに書き分けられるので設定は素直になります。

parallel

2026/06/25 に GitHub Actions に追加された構文で、1 つの job の中で複数の step を並列に実行できます。

https://github.blog/changelog/2026-06-25-actions-steps-can-now-be-run-in-parallel/

正確には、このとき追加されたのは background / wait / cancel / parallel の 4 つで、parallel は「step を background で起動して、直後に全部 wait する」パターンの糖衣構文です。

checkout や install を共有したまま、後段のタスクだけ並列にできるのが matrix / multi-job との違いです。
runner は 1 つのままなので、step はいくつでも並べられますが、実質的な並列度は runner の CPU 数で頭打ちになります。

比較のベースラインとして、並列化しない sequential (1 job で直列) も並べて 4 パターンを測ります。

検証

対象は React 19 + TypeScript の小さなコンポーネントライブラリで、lint / typecheck / test / build の 4 タスクを走らせます。
テストが数十秒かかる状態を作るため、コンポーネントを大量に render するテストを足してあります。

比較したのは次の 4 パターンです。

pattern構成
sequential1 job で 4 タスクを直列
parallel1 job で - parallel: ブロックにまとめて並列
matrixstrategy.matrix で 4 job
multi-job独立した 4 job

runner はすべて ubuntu-latest です、public リポジトリなので 4 vCPU あります。
各パターンを N=10 回ずつ交互に起動し、gh run view --json jobs で取れる各 job の開始・終了時刻から計測しました。

指標は 2 つです。

  • wall-clock: 最初の job が動き出してから全 job が終わるまでの実時間。
    runner のキュー待ちは含まれないので、体感の待ち時間より少し短めに出ます。
  • billable minutes: job ごとの実行時間を分単位で切り上げてから合計した値。
    GitHub の課金ルールに合わせた計算です。なお public リポジトリの standard runner は無料なので、今回のベンチ自体には課金は発生していません

実際のプロジェクトとは条件が異なるので、今回の結果をそのまま信用するのはおすすめしませんが、判断材料の一つになれば幸いです。

リポジトリ: https://github.com/sena-m09/gha-parallel-bench

今回の検証で使った parallel の書き方はこれだけです。

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: pnpm/action-setup@v6
      - uses: actions/setup-node@v6
        with:
          node-version-file: .nvmrc
      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - parallel:
          - name: Lint
            run: pnpm lint
          - name: Typecheck
            run: pnpm typecheck
          - name: Test
            run: pnpm test
          - name: Build
            run: pnpm build

matrix や multi-job は checkout と install がそれぞれの job で走るので、その分のオーバーヘッドが乗ります。
parallel は install までを共有できるのが構造上の利点です。
なお依存関係のキャッシュは使っていない素の状態で比較しているので、キャッシュを効かせれば matrix / multi-job のオーバーヘッドはもっと縮むはずです。

結果

wall-clock (秒)

patternmedianminmaxvs sequential (median)
sequential68.041.075.0
parallel63.047.069.0-7.4%
matrix56.543.067.0-16.9%
multi-job58.053.065.0-14.7%

billable minutes (job ごと切り上げして合計)

patternmedianminmax
sequential212
parallel212
matrix445
multi-job445

min / max を見ると分かるとおり、GitHub-hosted runner は実行ごとのぶれがかなり大きいです。
数 % の差は厳密な値ではなく目安として読んでください。

なぜ 7% しか速くならなかったのか

parallel は並列にした step が全部終わるまで wait するので、いちばん時間のかかる test の時間がそのまま parallel ブロックの時間になります。
ここまでは想定どおりでしたが、想定外だったのは、test を重くすると sequential との差がほとんど無くなったことです。

step ごとの時間を見るとこうなっていました。

tasksequentialparallel 内
test40.5 秒48 秒
lint5.5 秒16 秒
build4 秒12 秒
typecheck3 秒8.5 秒

parallel ブロックの合計時間は 48 秒で、たしかに test と同じです。
ただ、その test 自体が CPU の取り合いで直列時より 8 秒近く遅くなっています。
vitest はデフォルトでテストファイルを複数の worker で並列実行し、watch を使わない vitest run では worker 数の上限 (maxWorkers) が利用可能な CPU の数になります。
他の 3 タスクも軒並み 2〜3 倍の時間になっているので、複数のテストファイルが並列に走る間は test だけで CPU を使い切りやすく、そこへ lint / build / typecheck を相乗りさせてお互いを遅くし合った、と言えそうです。

実際、ストレステストを足す前 (test が 17 秒程度だったころ) にも同じ N=10 で測っていて、そのときの parallel は sequential 比 -11.8% でした (計測結果)。
test を重くするほど parallel で隠せる残りの仕事の割合が減り、差が縮んでいきます。
(並列化できない部分が全体の高速化の上限を決める、この現象はアムダールの法則というらしいですね。)

頭打ちしているのは matrix / multi-job も同じで、sequential 比 15〜17% しか速くなっていません。
test の job 単体で 41 秒 + セットアップ 15 秒かかるので、runner を何台並べてもそこが下限になります。
ストレステスト前の計測では -30% 前後だったので、こちらも test が重くなった分だけ効果が落ちています。

一方、billable minutes では順位が入れ替わります。
multi-job は runner が 4 つ動くので、課金対象時間も 4 job 分発生します。
parallel は 1 job のままなので中央値で 2 分と multi-job の半分で、sequential とは同額でした。
つまり今回の条件での parallel は、「sequential と同じコストで少し速い」のであって「multi-job に迫る速さで安い」わけではありませんでした。

ひとつ補足すると、この規模だと billable は分単位の切り上げの影響が大きいです。
60 秒前後の job が 1 分になるか 2 分になるかで比率が大きくぶれるので、「半分」という数字よりも「job の本数がそのまま課金の本数になる」という構造に着目した方が良さそうです。

使い分け

ここまでの結果を踏まえて、どう使い分けるかを考えてみます。

まず、1 つのタスクが支配的になっていないかを見ます。
支配的なら、今回の実測のとおりどのパターンでも最長タスクで頭打ちします。
4 タスクをどう並列にするかより、そのタスク自体の分割を検討するほうが効果があります。

そのうえで、何を優先するかで選びます。

  • 待ち時間を最優先で減らしたい: multi-job か matrix。最長タスクの時間までは縮みますが、billable は job の本数分増えます
  • コストを据え置いて少し速くしたい: parallel。既存 workflow に数行足すだけで済みます。ただし vitest のように単体で CPU を使い切るタスクと相乗りさせると効果が出ません
  • タスク間に依存がある、あるいは全体が数十秒で終わっている: sequential のままで良いと思います。切り替える手間のほうが高くつきます

なお今回試したのは「4 タスクを素朴に parallel に入れる」構成だけです。
重い test は直列のまま軽い 3 タスクだけを parallel にする構成や、vitest の maxWorkers を絞って他のタスクに CPU を譲る構成なら結果が変わる可能性があるので、今後試したいところです。

private リポジトリで有料の分を消費しているのか、public でフリー枠なのか、CI 待ちが開発の律速になっているのか、で選択は変わります。

学び

一つは、速度改善とコストの削減は別の軸だということです。
最速だった multi-job / matrix は billable も 4 job 分に増え、parallel は sequential と同額のまま少しだけ速くなりました。
「どれが一番いいか」ではなく、自分のプロジェクトが待ち時間とコストのどちらで困っているかを明確にすることで、選ぶ手段を決めやすくなりそうです。

もう一つは、GitHub Actions 側で並列にすれば単純に速くなるわけではない、ということです。
vitest のようにツール自身が CPU を使い切る前提で並列化している場合、その外側で parallel を足しても CPU の取り合いになるだけで、実測でも test は直列時より遅くなりました。
並列化を足す前に、いま走っているタスクがすでに CPU をどう使っているかを見ておく必要があることを学べました。

なお今回のベンチは N=10、対象も小さい TypeScript ライブラリ 1 件なので、傾向として読んでいただきたいです。

Gaji-Labo では「こうだろう」という思い込みによるこだわりを持たず、その時に必要な成果は何かを理解した上で手段を選ぶことを大切にしています。
今回も「並列にすれば速くなるはず」で止まらずに実測したことで、自分のプロジェクトで何を優先すべきかを判断する材料を持てました。
新しい機能が出たときに鵜呑みにも食わず嫌いにもならず、手を動かして確かめる習慣はこれからも続けていきたいです。

参考

Gaji-Labo は Next.js 開発の実績と知見があります

フロントエンド開発の専門家である私たちが御社の開発チームに入ることで、バックエンドも含めた全体の開発効率が上がります。

「既存のサイトを Next.js に移行したい」
「人手が足りず信頼できるエンジニアを探している」
「自分たちで手を付けてみたがいまいち上手くいかない」

フロントエンド開発に関わるお困りごとがあれば、まずは一度お気軽に Gaji-Labo にご相談ください。

オンラインでのヒアリングとフルリモートでのプロセス支援にも対応しています。

フロントエンドの相談をする!


Gaji-Labo フロントエンドエンジニア向けご案内資料

Gaji-Laboでは、 Next.js 経験が豊富なフロントエンドエンジニアを募集しています

弊社では Next.js の知見で事業作りに貢献したいフロントエンドエンジニアを募集しています。大きな制作会社や事業会社とはひと味もふた味も違う Gaji-Labo を味わいに来ませんか?

Next.js の設計・実装を得意とするフロントエンドエンジニア募集要項

もちろん、一緒にお仕事をしてくださるパートナーさんも随時募集中です。まずはお気軽に声をかけてください。お仕事お問い合わせや採用への応募、共に大歓迎です!

求人応募してみる!

タグ


投稿者 Sena Murakami

アシスタントフロントエンドエンジニア。 Webマーケティング会社でマークアップエンジニアとして経験を積み、Gaji-Laboに入社。デザインの意図を汲み取ったマークアップが得意です。チームを俯瞰してリードできるエンジニアになることが目標です。趣味はバドミントンやバレーボール、キャンプなど。