0

時間予算を保持しているモデル (PurchaseOrder - 略して PO) があります。ユーザーはこの予算に時間レコードを追加できます。時間レコードごとに残りの予算が減ります。

残りの予算を更新するためのシグナルを実装しました。時間レコードを追加すると、それに応じて予算が削減されます。計算には時間がかかる可能性があるため、このタスクにはスレッドを使用しました。

def update_po_remaining_value(sender, instance, **kwargs):
    CalculatePOThread(sender, instance).start()   
post_save.connect(update_po_remaining_value, sender=HourRecord)       
post_delete.connect(update_po_remaining_value, sender=HourRecord) 

スレッド CalculatePOThread は、時間レコード セットを取得し、予算から合計時間レコード セットを差し引くことによって、残りの PO 予算値を計算しています。

hr_set = HourRecord.objects.filter(purchase_order = po)

私の dev.workspace では、これは完全に正常に機能します。本番環境では、post_save 接続も問題なく動作しますが、post_delete シグナルで奇妙な問題が発生しています。クエリ HourRecord.objects.filter(purchase_order = po) によって返される時間レコードの合計に、CalculatePOThread スレッドをトリガーした削除された時間レコードが含まれていることがよくあります。

とにかく、クエリを実行する前にスレッドに6秒の遅延を追加して、動作を回避しました。time.sleep(6)。

なぜこのような状況が発生するのか、誰にも分かりますか? レコードがデータベースから実際に削除される前に、post_delete シグナルがトリガーされたようです..!? しかし、これは Django のバグであり、これが私の最後の推測です。

4

1 に答える 1

1

言うのは難しいですが、スレッドセーフの問題が発生したと思います。長時間実行されるタスクを処理するためにスレッドをスポーンする場合、それが完了しようとしている間、同様のスレッドが同じタスクで簡単に起動される可能性があることに注意する必要があります。一般に、スレッドを操作するときは、スレッドのフットプリントを最小限に抑える必要があります。つまり、データベースの状態などに大きく依存しないようにする必要があります。

データベースへのアクセス必要な場合(この場合)、データベースが同時に混乱するのを防ぐためにロックを設定する必要があります。ただし、Django 1.1を実行している場合、これははるかに困難になります。Django 1.1でテーブルレベルのロックを実現する方法は、実行しているデータベースサーバーに依存し、独自の質問が必要になります。

于 2012-05-07T20:24:14.537 に答える