この記事は、連載「追わない技術」の第 5 回です。うまくいかない症状と、その対処を一つずつ並べています。各回はファイルやスクリプトを一つ置けば完結します。その仕組みがなぜ要るのかは、置いたあとに解説を読めば分かります。連載の全体像と各回の一覧は序論にあります。
今回は、1 つの仕事を何人もの作業者へ割って、同時に走らせる話です。前回は「自分でやるか、1 人に渡すか」でした。今回は渡す先が n 人になります。前回出した「渡すと 1 往復あたり約 2 倍」は、もう繰り返しません。今回足すのは、割った先の値段が、どこで、なぜ増えるかだけです。割ることの値段は人数 × 1 人ぶんの会話の長さで決まります。人数は割ると決めた瞬間に決まり、会話の長さは渡し方で決まります。そして待たせると切れるので、止まっている間に使い回しの期限が切れ、再開のたびに会話ぜんぶを作り直すことになります。
先に、題を否定しておきます。速さが要る場面では、割るべきです。割らないのは、速さを買う必要がないときだけです。
そして値段は、払う覚悟があるなら払ってよい性質のものです。
そのうえで白状します。作業者どうしが互いに話しながら進む形を、私は本格的に使ったことがありません。だから、その形についての実測は 1 つも出しません。出すのは、1 人に渡すのと n 人に割るのとで何が違うかと、その違いがどこで値段になるかの 2 つです。
一つ思い出してみてください。
4 つに割ったとき、仕事は 4 倍速く終わりましたか。
値段のほうは、4 倍になっていましたか。
私の手元では、速さは 2.5 倍まで、量はほぼ 4 倍でした。
先に持って帰るものを言っておきます。値段は「人数 × 1 人ぶんの会話の長さ」で決まります。人数のほうは割ると決めた時点で終わりなので、手を入れられるのは会話の長さだけです。以降はその 2 つを別々に数えます。
CC BY 4.0
1 人に渡す / n 人に割る / 話し合わせる —— 違いは 3 つだけです
先に、言葉の整理をします。この 3 つは地続きで、増えるものが 1 つずつ足されていく関係です。
| 増えるもの | 誰が待つか | |
|---|---|---|
| 1 人に渡す | 会話が 1 本増える | こちらが 1 人を待つ |
| n 人に割る | 会話が n 本増える。⭐ 合流点ができる | こちらがいちばん遅い 1 人を待つ |
| 話し合わせる | 上に加えて、互いの発言が互いの会話に入る | ⚠️ 互いに待ち合う |
ここで大事なのは、どれも「会話が増える」ことです。機能に値札が付いているわけではありません。値段は、増えた会話の中身が読み直される量として出ます。以降はそれを数えます。
4 人に割ると、読ませる量はほぼ 4 倍になります
前回と同じ記録を、まとまりの側から数え直しました。新しく実験は回していません。ここでいう「まとまり」は、同じ 1 回の発言で、いっぺんに起動した作業者のかたまりのことです。46 セッションぶんで 164 のまとまり / 342 人ありました。
ここは数え方を 2 通り出さないと嘘になります。同じ入力でも、初めて読ませる部分と、前の往復から使い回せる部分があり、後者は安く課金されます。安いだけで、ゼロではありません。
| いっぺんに出した人数 | まとまりの数 | 初めて読ませた量 | 1 人だけのとき比 | 使い回しまで足した量 | 1 人だけのとき比 |
|---|---|---|---|---|---|
| 1 人 | 90 | 32,466 | 1.00 倍 | 282,486 | 1.00 倍 |
| 2 人 | 16 | 60,998 | 1.88 倍 | 675,063 | 2.39 倍 |
| 3 人 | 13 | 78,870 | 2.43 倍 | 1,075,737 | 3.81 倍 |
| 4 人 | 44 | 93,860 | 2.89 倍 | 1,072,771 | 3.80 倍 |
左の列だけを見て「4 人に割っても 2.89 倍で済む」と読むのは間違いです。右の列は 3.80 倍 —— ほぼ人数どおりでした。
減っているのは量ではなく、その量に付く値段のほうです。割った人数ぶんの入力は、ちゃんと人数ぶん発生しています。安く済んでいる部分がどこから来ているのかは、次の節で出します。
表を見て引っかかるところが 1 つあるはずです。3 人(3.81 倍)と 4 人(3.80 倍)がほぼ同じです。人数が 1 人増えても、量が増えていません。これは次の次の節で分かります。値段を決めているのは人数だけではないからです。
もう 1 つ、この表だけでは決まらないことがあります。まとまりが大きいときほど、1 人に渡した仕事が軽かっただけかもしれません。何人で割るかを決めていたのは私だからです。仕事の重さと関係のない数は、次の節にあります。
頭を温めるのは、いつも最初の 1 人だけでした
同じ記録から、今度は使い回せた量のほうを見ます。こちらは何を頼んだかと無関係なので、上の表の弱いところを埋められます。
| 1 手目に使い回せた量(中央値) | 使い回しゼロだった割合 | |
|---|---|---|
| 1 人だけ出したとき(90 人) | 16,421 | 29% |
| いっぺんに出して、最初に動き出した 1 人(74 人) | 3,183 | 50% |
| そのあとに続いた人(178 人) | 24,542 | 6% |
8 倍の差です。どの作業者にも、最初に同じ説明書きが渡ります。その説明書きを読み込ませているのは、実際に最初に動き出した 1 人だけで、あとの人はそこに乗っていました。
これが、さっきの表で「初めて読ませた量」だけが人数を下回っていた理由です。量が減ったのではありません。同じ量が、2 人目以降は安いほうの数え方に移っただけです。
flowchart TD A["いっぺんに 4 人へ割る"] --> B["最初に動いた 1 人<br/>⚠️ 説明書きを読み込ませる<br/>使い回せた量 3,183<br/>半分はゼロから"] A --> C["あとに続いた 3 人<br/>⭐ その部分に乗れる<br/>使い回せた量 24,542<br/>ゼロは 6%"] B --> D["初めて読ませた量は<br/>2.89 倍で済む"] C --> D D --> E["⚠️⚠️ ただし使い回しまで足すと 3.80 倍<br/>減ったのは量ではなく単価"]
順番の取り方に落とし穴があります。いっぺんに出した相手には発注の順序がありません(同じ 1 回の発言だからです)。記録のファイル名順で並べると、この差は消えます。
実際にそうすると 24,538 と 24,540 になって、差が無いという結論が出ます。並べるのは「実際に動き出した順」です。
掛け算のもう片方 —— 1 人ぶんの会話の長さ
ここが今回いちばん大事な節です。人数の側はさっき見ました。今度は右側——同じ 342 人を、1 人ぶんの会話が何往復あったかで並べ直します。表に並ぶのは 339 人です(1 往復で終わった 3 人は、1 往復あたりが出せないので外しました)。
| 1 人ぶんの往復 | 人数 | 読み直された履歴の合計(中央値) | 1 往復あたり(中央値) |
|---|---|---|---|
| 2〜3 往復 | 17 | 64,238 | 21,577 |
| 4〜6 往復 | 118 | 173,638 | 32,740 |
| 7〜12 往復 | 110 | 295,110 | 35,550 |
| ⚠️⚠️ 13 往復以上 | 94 | 1,538,165 | 54,243 |
2〜3 往復と 13 往復以上で、24 倍です。往復の数は 5 倍ほどしか違いません。
理由は右の列にあります。1 往復あたりの重さまで、一緒に増えています(21,577 → 54,243)。会話が伸びると、そこまでの全部が毎回読み直されるので、往復が増えるほど 1 往復が重くなるのです。だから合計は足し算ではなく、掛け算で効きます。
さっきの表で 3 人と 4 人がほぼ同じだった理由は、これです。人数を 1 人増やしても、その 1 人が短く終われば量は増えません。逆に、人数を増やさなくても、1 人が長く喋れば増えます。
手を入れられるのは、こちら側だけです。人数は割ると決めた時点で終わりですが、何往復で終わる形にして渡すかは、渡す前に決められます。
中央値 8 往復。そこが払っている場所です
手元の 342 人は、1 人あたり中央値 8 往復でした。⚠️ 最も長い 1 人は 107 往復です。
用途ごとに並べると、はっきりします。
| 用途 | 人数 | 往復(中央値) | 読み直しの合計(中央値) |
|---|---|---|---|
| 翻訳(1 人 = 1 言語ぶん全部) | 5 | 55 | 4,840,746 |
| 用途を書かずに渡した調べもの | 64 | 20 | 1,142,747 |
| 実験(材料を先に作って渡す) | 139 | 6 | 206,526 |
意外なほうから書きます。私はこれを外しました。私は「手順書と受け入れテストまで用意した仕事がいちばん安いはずだ」と思っていました。翻訳がそれです。渡す一覧も、差し込みのスクリプトも、合否を出す受け入れテストも、全部こちら側に用意してあります。
それがいちばん高くつきました。理由は 1 つで、1 人に 1 言語ぶんを丸ごと任せたので、55 往復かかったからです。
逆にいちばん安いのは、実験のために出した作業者でした。材料はこちらがスクリプトで作り、渡された側は 1 回やって返すだけにしてあります。6 往復です。
準備の丁寧さでは決まりませんでした。決めていたのは、渡した仕事が何往復で終わる形かです。
割ると速くなるのは本当です。ただし止まるのは、いちばん遅い人です
速さの側も出します。ここを出さないと片側だけの話になります。
| いっぺんに出した人数 | まとまりが終わるまで | 同じ人数を 1 人ずつ順にやったら | 縮んだ倍率 |
|---|---|---|---|
| 2 人 | 129.9 秒 | 197.9 秒 | 1.52 倍 |
| 3 人 | 99.1 秒 | 258.4 秒 | 2.61 倍 |
| 4 人 | 146.6 秒 | 372.4 秒 | 2.54 倍 |
4 人に割っても、縮むのは 2.54 倍です。3 人に割ったとき(2.61 倍)より悪くなっています。
理由はまとまりの中のばらつきに出ます。
| いっぺんに出した人数 | いちばん速い人 | まん中の人 | いちばん遅い人 | 遅い ÷ まん中 |
|---|---|---|---|---|
| 2 人 | 82.9 秒 | 98.9 秒 | 129.9 秒 | 1.31 倍 |
| 3 人 | 78.5 秒 | 85.4 秒 | 99.1 秒 | 1.16 倍 |
| 4 人 | 78.5 秒 | 88.4 秒 | 146.6 秒 | 1.66 倍 |
4 人に割ったとき、まん中の人は 88.4 秒で終わっています。それでも、まとまりが終わるのは 146.6 秒です。こちらが待っているのは、まん中の人ではなく、いちばん遅い人だからです。人数を増やすほど、外れくじを引く回数が増えます。
待たせると、使い回せる部分が消えます
ここまで「使い回せる部分があるから安い」と書いてきました。その部分には期限があります。
作業者へ「続き」を送った 68 回を、送るまでにその人を待たせた時間で分けました。
| 待たせた時間 | 回数 | 再開した 1 手の「初めて読ませた量」 | 同・使い回せた量 |
|---|---|---|---|
| 5 分未満 | 60 | 346 | 39,058 |
| ⚠️⚠️ 5 分〜1 時間 | 8 | 15,104 | 24,879 |
44 倍です。待たせている間に使い回しの期限が切れ、再開した 1 手が、そこまでの会話をまるごと作り直しています。
母数は 8 回しかありません。数そのものは読まず、向きだけを見てください。
ここが、話し合わせる形でいちばん効くところです。作業者どうしを会話させると、片方が相手の返事を待つ間、必ず止まります。止まっている間に期限が切れ、再開のたびに会話ぜんぶを作り直すことになります。
そして前の節のとおり、会話が長いほど作り直す量は大きくなります。
ただし、これは仕組みからの推論です。手元にあるのはこちらから作業者へ送った割り込みだけで、作業者どうしの待ち合いは 1 度も測っていません。
会話させないなら、それは「チーム」である必要がありません
ここまでを裏返すと、判断がはっきりします。
その形を選ぶ理由は、互いに会話させたいときだけです。会話させないなら、増えているのは会話の本数だけなので、ただ n 人へ同時に渡すのと同じです。同じことなら、待ち合いが起きない渡し方のほうを選びます。
| やりたいこと | 選ぶ形 |
|---|---|
| ⭐ 同じ種類の仕事を、まとめて速く片づけたい | n 人へ同時に渡すだけ。⚠️ 会話させる必要はありません |
| ⚠️ 片方の結果を見ないと、もう片方が決められない | ⭐⭐ 割らずに 1 本でやります。 会話させて解くと、待ち合いのぶんが両方に積まれます |
| ⚠️⚠️ どうしても互いに相談させたい | ⭐ 速さのために払う形です。⚠️ そのとき増えるのは、往復(1 人ぶんの会話が伸びる)と、待ち合いのたびの作り直しの 2 つです |
原理: 値段は「人数 × 1 人ぶんの会話の長さ」です
ここまでの数は、1 つの掛け算にまとまります。
⭐⭐⭐ 割ることの値段は、人数 × 1 人ぶんの会話の長さ。人数は割ると決めた瞬間に決まり、会話の長さは渡し方で決まる。そして終わる時刻を決めているのは、いちばん遅い 1 人だけである。
この回に出た 2 つの数は、この式の左と右です。人数の側は割った時点でほぼ人数どおり(4 人で 3.80 倍)。会話の長さの側は渡し方しだいで 24 倍動きます。動かせるのは右だけです。
flowchart TD
A["n 人に割る"] --> B["会話が n 本に増える"]
B --> C{"1 本が<br/>何往復で終わるか"}
C -- "短い(数往復)" --> D["⭐ 増えるのは本数だけ<br/>2〜3 往復で 64,238"]
C -- "長い(十数往復)" --> E["⚠️⚠️ 本数 × 長さで効く<br/>13 往復以上で 1,538,165"]
A --> F["合流点ができる"]
F --> G["⚠️ 終わるのは<br/>いちばん遅い 1 人が終わったとき"]
速さが要るなら、払ってよい値段です。
ただし、速さが要る場面には、これを丁寧に確かめている時間がありません。だから実際には、どこが無駄になっているかを知らないまま払うことになります。せめて、どこで増えるのかだけは先に知っておく——この節はそのために書きました。
値段を増やさずに並列でやる形
前の回で書いた打ち手が、そのまま効きます。新しい話ではありません。同じものをもう一度当てるだけです。
- 渡す前に、材料をこちらで作っておく(第 3 回の「パターンを明文にして渡す」と同じ形)。探すところから任せると、探すぶんの往復が全部その人の会話に積まれます
- 1 人に渡すのは、1 回で返せる大きさまで(前回の「本体が持っていないものを集める仕事だけ渡す」と同じ線引き)。1 言語ぶん全部、ではなく、1 ファイルぶんです
- 合否の判定はこちらでやる。判定まで任せると、判定のやり直しがその人の会話に積まれます
- 重さをそろえてから割る。1 つだけ重いものが混ざっていると、残りが終わっても待つことになります
これをやると、上の表の「実験のために出した作業者」の側(6 往復 / 206,526)に寄ります。同じ人数でも、渡し方だけで 23 倍違いました。
検証手順: 掛け算の左と右を、別々に数える
前提
- 作業者をいっぺんに複数起動できる環境があり、その記録(読み込ませた量・使い回した量・往復・時刻)が残っていること。残っていないなら、この手順は使えません
- 「まとまり」は、同じ 1 回の発言でいっぺんに出したかどうかで束ねます。発注の時刻で束ねてはいけません(並列に出したものが記録上ばらけて、全部 1 人扱いになります)
- 1 まとまりでは決まりません。同じ人数のまとまりを、複数回ぶんまとめて見ます
所要時間: 30 分(記録が手元にある場合)
手順
- 記録から、まとまりを人数ごとに分けます
- 人数ごとに、2 通りで中央値を出します —— 初めて読ませた量だけと、使い回した量まで足したもの。1 人のときを 1.00 として、それぞれ何倍かを出します
- 2 で出た 2 つの倍率と、人数そのものを比べます。片方だけを見て「人数を下回った」と読まないこと
- まとまりの中で、最初に動き出した 1 人と、あとに続いた人に分けて、1 手目に使い回せた量を出します。並べる順は「実際に動き出した順」です(発注順・ファイル名順では差が消えます)
- 人数をいったん忘れて、作業者を「1 人ぶんの往復」で階級分けします(2〜3 / 4〜6 / 7〜12 / 13 以上)。階級ごとに、読み直された履歴の合計と、それを往復で割った値を出します
- 各まとまりについて、いちばん遅い人の所要時間 ÷ まん中の人の所要時間を出します
- 人数ごとに、まとまりが終わるまでの時間と、同じ人数を 1 人ずつ順にやった場合の合計を並べます
合格条件(すべて満たすこと)
- 手順 3 で、2 つの倍率が離れている(同じなら、使い回した量を数えられていません)
- 手順 4 で、最初に動いた 1 人のほうが、使い回せた量が少ない(同じなら、並べる順を間違えています)
- 手順 5 で、往復が多い階級ほど「1 往復あたり」も大きい(同じなら、履歴の再送を数えられていません)
- 手順 6 の比が 1.0 より大きいまとまりが 1 つ以上ある。全部 1.0 なら、割った先の重さが完全にそろっているので、この回の話は要りません
合格しなかったとき
- 2 つの倍率が同じになる —— 使い回した量を別に数えていません。初めて読ませた量と、使い回した量は、記録の別の欄にあります
- 最初の 1 人とあとの人で差が出ない —— 発注の順で並べています。いっぺんに出した相手に発注の順序はありません。最初の返事が返ってきた時刻で並べ直してください
- 往復が増えても「1 往復あたり」が変わらない —— 使い回せた量ではなく、新しく読み込ませた量だけを見ています。読み直された履歴のほうを数えてください
- いちばん遅い人が、まとまりの終わりと一致しない —— 終わりを本体側に結果が返った時刻で採っています。作業者の最後の発言で採り直してください
後始末
- 集計に使った中間ファイルを削除します。記録そのものは消さないでください
- 結果は日付つきで残します。記録は増え続けるので、同じスクリプトを明日走らせると数が動きます
注意: この数字が言えないこと
いちばん大きい弱点を先に書きます。作業者どうしを話し合わせる形について、私は何も測っていません。本格的に使ったことがないからです。この回に書いたのは「n 人に割る」までで、その先は一般論だけです。
これは統制された実験でもありません。同じ仕事を「1 人でやった場合」と「4 人で割った場合」で並べて測ったのではなく、実際に割った 164 まとまりを後から数え直しただけです。
何人で割るかを決めていたのは私です。だから「1 人あたりが安くなる」は、大きく割ったときほど 1 人に軽い仕事を渡していただけかもしれません。この向きの偏りは外せませんでした。
偏りの影響を受けない数が 2 つあります。
- 最初に動いた 1 人と、あとに続いた人で、使い回せた量が 8 倍違う —— これは何を頼んだかと無関係です。説明書きは全員に同じものが渡ります
- いちばん遅い人が、まん中の人の 1.66 倍かかる —— これはまとまりの中の比なので、まとまりどうしの重さがそろっていなくても比較になります
往復の表にも、外せない偏りが 1 つあります。難しい仕事だから往復が増えたのか、往復が増える渡し方をしたから増えたのか、この数字だけでは決まりません。私が言えるのは「往復が増えると掛け算で効く」までで、「渡し方を変えれば必ず減る」ではありません。
逆に、「3.80 倍」と「2.54 倍」は、そのままでは持ち出せません。使えるのは、自分の手元で同じ数え方をしたときの、自分の数です。
前回を 1 か所直しておきます。前回の初稿では、私はこの割り方を「同時に出した 1 体目(164 人)」と書きました。前回の表は、この回を書いた日に 3 行へ直しました。いま第 4 回を開くと、そこにあるのは直したあとの表です。その 164 人には、1 人しか出していないまとまりの 90 人が混ざっていました。混ざりを外して割り直すと、差はむしろ 8 倍に広がります。前回の結論(あとに続いた人は最初の人に乗れる)は変わらず、強くなる向きでした。
もう 1 つ。5 人で割ったまとまりは、記録に 1 つしかありませんでした。数は出ていますが、1 件なので読みません。この回の表に 5 人の行が無いのは、そのためです。
CC BY 4.0 はここまで
割らなくなったもの
- 「とりあえず 4 つに割る」のをやめました。割った時点で、読ませる量はほぼ人数どおり(3.80 倍)に決まります。速さのほうは、いちばん遅い 1 人が決めます
- 1 人に「まるごと 1 つ」を渡すのをやめました。1 言語ぶん全部を任せると 55 往復かかり、読み直しは 480 万を超えました。同じ仕事を、1 回で返せる大きさに切って渡します
- 重さがそろっていないものを割るのをやめました。1 つだけ重いものが混ざっていると、残りの 3 人が終わっても待つことになります
- 「手順書と受け入れテストを用意したから安いはずだ」と考えるのをやめました。用意の丁寧さでは決まりません。決めているのは往復の数です
- 割るのをやめていない仕事もあります —— 重さがそろっていて、互いを見なくてよくて、1 回で返せる調べものです。そこでは量 3.80 倍・速さ 2.54 倍です。釣り合わせているのは、使い回せる部分が安いことのほうです
人を増やせば速くなる、という感じは、たいてい正しく見えます。3 人が先に終わって、待っている時間が見えないからです。
そして値段のほうは、割ると決めた時点で人数ぶん確定していて、そこから先はいちばん長く喋った 1 人が決めていました。
次回は「途中でレビューさせない技術」。私は、作業の途中で別の作業者に見直させるのをやめました。渡した先の 8 割以上は別のモデルで、こちらがすでに守れていたものを知らないからです。