4

私はあまり成功せずにいくつかの解決策を模索しました。2つのPythonプロセス(サブプロセスからPopenを使用して作成)とpersone、2つの列を持つ1つの行を含む1つのmysqlテーブル(と呼ばれる)がありますAge:0, id:1。1つのプロセスがその行を選択し、その行を取得して1つインクリメントします。それは1000回行います。2つ目は同じことを行いますが、代わりにデクリメントします。各プロセスを並行して実行します。

理論的には、最終的には年齢がゼロのままであることを望みます。問題は、mymain.pyの最後で100から-100の間のランダムな値を取得し続けることです。これは、同時に行われるアクセスがあり、データベースが破損していることを意味すると思います。何が足りないのかしら?

これをテストするために使用するコードは次のとおりです。

ajoutAge.py

import MySQLdb as lite

num=1000
connexion = lite.connect(host="localhost", user="root", passwd="123", db="test")
with connexion:
    for i in range(num):
       cur = connexion.cursor()
       cur.execute('start transaction')
       cur.execute('select Age from persone where id=1')
       age = cur.fetchone()[0]
       cur.execute('update persone set Age='+str(age+1)+' where id=1')
       # cur.execute('rollback')
       cur.execute('commit')
print "ajout Done"

retraitAge.py

import MySQLdb as lite

num=1000
connexion = lite.connect(host="localhost", user="root", passwd="123", db="test")
with connexion:
    for i in range(num):
        cur = connexion.cursor()
        cur.execute('start transaction')
        cur.execute('select Age from persone where id=1')
        age = cur.fetchone()[0]
        cur.execute('update persone set Age='+str(age-1)+' where id=1')
        cur.execute('commit')
print "retrait Done"

mymain.py

from subprocess import Popen

a=Popen("python ajoutAge.py", shell=True)
aa=Popen("python ajoutAge.py", shell=True)
b=Popen("python retraitAge.py", shell=True)
bb=Popen("python retraitAge.py", shell=True)

a.communicate()
aa.communicate()
b.communicate()
bb.communicate()
print "Main done"

私のテーブルは、ストレージエンジンとしてInnoDBを使用しています。

4

1 に答える 1

3

競合状態を作成しています。

現在の年齢を選択するたびに、それとUPDATEの間に一瞬があります。その一瞬で、他のプロセスは値を更新する可能性があります(そして明らかに時々そうです)。

したがって、最初のプロセスでは、値をage + 1に更新すると、わずかに古い値に基づいて増分されます。

これを修正するには、いくつかのオプションがあります。

  • SELECT ... FOR UPDATE、行をロックし、トランザクションを終了する前に他のプロセスが行を変更できないようにします。SELECTトランザクションをコミットしないようにする必要があります。これにより、ロックが解放され、別の競合状態が発生する可能性があります。

  • UPDATE persone SET age = age+1 WHERE id=1(またはage=age-1もちろん)。言い換えると、値を変更するのと同じ式で値を読み取るため、アトミックであり、並行プロセスが「侵入」してその間に変更することはできません。

于 2013-03-12T00:44:04.000 に答える