Yueser ← プロンプト一覧へ

AI / コーディングとデバッグ

並行性と競合状態のレビュー

2つのリクエストが同時に届くと仮定し、共有状態を1つずつ辿る

次のコードの並行安全性をレビューしてください。方法:2つのリクエストが同じミリ秒に届くと仮定し、共有状態を順に辿ります。次をお願いします:1)共有される可変状態をすべて挙げる(メモリ上の変数、キャッシュ、データベースの行、ファイル);2)確認と使用のあいだに隙間がある箇所(読んでから書く)を示す;3)どの程度の並行数で表面化するか、表面化したときに何が起きるかを述べる;4)最小の修正方法(ロック、一意制約、アトミック操作、冪等化)と、それぞれの代償を示す。

```
[コードを貼り付けてください]
```
使い方

並行数の少ないプロジェクトでも一度は通しましょう。「読んでから書く」穴は、たいていトラフィックが増えてから炸裂します。

向いている場面

  • 「読んでから書く」処理があるとき。在庫の減算、クーポンの取得、冪等な注文作成などです。
  • 単一ノードのテストは必ず通るのに、マルチインスタンス配備や負荷試験の後に重複データが出始めたとき。

向いていない場面

  • 単一プロセスで共有状態がなく、純粋関数だけなら、レビューする並行性の問題はありません。
  • 分離レベルやロック待ちだと分かっているなら、コード全体ではなくロックとトランザクションを見ます。

例

入力
def claim_coupon(user_id, coupon_id):
    if db.exists("select 1 from claims where user_id=? and coupon_id=?", user_id, coupon_id):
        return "already"
    if db.count("select count(*) from claims where coupon_id=?", coupon_id) >= 100:
        return "sold_out"
    db.insert("claims", user_id=user_id, coupon_id=coupon_id)
    return "ok"
得られるもの
共有される可変状態は claims テーブルと在庫数です。check-then-act の隙間は 2 か所あります。同じユーザーの 2 つのリクエストがどちらも exists を通過する点、在庫が 99 のときに 2 つのリクエストがどちらも count<100 を通過する点です。2 インスタンスで秒間 10 リクエスト程度のクーポン争奪で表面化し、現象は重複取得と超過配布です。最小の修正は `(user_id, coupon_id)` の一意制約で受け止め、`INSERT ... SELECT ... WHERE count < 100` の 1 文で原子的に書くことです。代償は競合時のリトライです。

よくある誤用

  • 「並行性の問題を見てください」とだけ言い、配備形態(インスタンス数、Redis ロックの有無)を伝えないと、単一ノードで安全なコードが危険と判定されます。
  • 「ロックを追加」と言われてプロセス内ロックを足すと、マルチインスタンスでは何も守れません。

こう変えると効く

  • 「3 インスタンス、共有キャッシュなしと仮定して」と加えると、プロセス内の変数も共有状態として数えます。
  • 「安定して再現する負荷試験の概要(同時数、リクエスト順)を出して」と頼むと、抽象的なリスクが検証可能な実験になります。

同じ分野のプロンプト