我使用ZODB作为要通过are服务修改的对象的持久存储。下面是我把这个问题减少到的一个例子。增量函数是从多个线程中调用的函数。我的问题是,当从两个线程同时调用增量时,对于不同的键,我将得到冲突错误。
我认为这应该是有可能解决这个问题,至少只要不同的键被修改,以适当的方式?如果是这样的话,我没能找到一个关于如何.(zodb文档似乎有些分散在不同的站点上:/ )
很高兴有任何想法..。
import time
import transaction
from ZODB.FileStorage import FileStorage
from ZODB.DB import DB
from ZODB.POSException import ConflictError
def test_db():
store = FileStorage('zodb_storage.fs')
return DB(store)
db_test = test_db()
# app here is a flask-app
@app.route('/increment/<string:key>')
def increment(key):
'''increment the value of a certain key'''
# open connection
conn = db_test.open()
# get the current value:
root = conn.root()
val = root.get(key,0)
# calculate new value
# in the real application this might take some seconds
time.sleep(0.1)
root[key] = val + 1
try:
transaction.commit()
return '%s = %g' % (key, val)
except ConflictError:
transaction.abort()
return 'ConflictError :-('发布于 2013-08-07 10:18:30
这里有两个选项:实现冲突解决,或者用新数据重试提交。
冲突解决只适用于您存储在ZODB中的自定义类型,并且只有当您知道如何将更改合并到新更改的状态时,才能应用。
ZODB查找自定义类型上的_p_resolveConflict()方法,并使用旧状态调用该方法、与之冲突的保存状态以及试图提交的新状态;您应该返回合并状态。对于一个简单的计数器(如您的示例中的例子),这将与使用新旧状态之间的更改更新保存的状态一样简单:
class Counter(Persistent):
def __init__(self, start=0):
self._count = start
def increment(self):
self._count += 1
return self._count
def _p_resolveConflict(self, old, saved, new):
# default __getstate__ returns a dictionary of instance attributes
saved['_count'] += new['_count'] - old['_count']
return saved另一种选择是重试提交;您希望限制重试的次数,并且您可能希望将其封装在方法的修饰器中,但基本原则是循环到极限,根据ZODB数据进行计算(在发生冲突后,这些数据将在需要时自动读取新的数据),然后尝试提交。如果提交成功,则完成:
max_retries = 10
retry = 0
conn = db_test.open()
root = conn.root()
while retry < max_retries:
val = root.get(key,0)
time.sleep(0.1)
root[key] = val + 1
try:
transaction.commit()
return '%s = %g' % (key, val)
except ConflictError:
retry += 1
raise CustomExceptionIndicatingTooManyRetrieshttps://stackoverflow.com/questions/18098979
复制相似问题