I have a bunch of DB entities that are loaded into DB objects. The same DB entity may be loaded into more than DB object. Periodically a DB entity will require special processing. This processing must be performed by one thread at a time. Locking is in order here.
我有一堆数据库实体加载到数据库对象中。可以将相同的DB实体加载到多个DB对象中。 DB实体需要定期进行特殊处理。此处理必须一次由一个线程执行。在这里按顺序锁定。
EDIT: Important note: the process calls a slow web service. This is what I'm trying to prevent concurrency. I don't see how this can be done safely w/o locks.
编辑:重要说明:该过程调用慢速Web服务。这就是我试图阻止并发的原因。我不知道如何安全地完成没有锁。
So I create an “padlock” object that will be referenced by the DB objects for locking. The padlock object is entity based so that two or more DB objects for the same entity will use the same padlock object. I’m storing these padlocks in a dictionary object using the DB entity’s ID as the key. The padlock object is just a simple string object as well. Is this the right approach? I'm thinking I'm either over engineering or simplifying this. If the approach is correct, how does this code look? It works, but I've yet to test it under load.
所以我创建了一个“挂锁”对象,DB对象将引用该对象进行锁定。挂锁对象是基于实体的,因此同一实体的两个或多个DB对象将使用相同的挂锁对象。我使用数据库实体的ID作为密钥将这些挂锁存储在字典对象中。挂锁对象也只是一个简单的字符串对象。这是正确的方法吗?我想我要么过度工程,要么简化这个。如果方法是正确的,那么这段代码看起来如何?它有效,但我还没有在负载下测试它。
Thanks :)
public static func(CustomObject o)
{
if (ReadyForUpdate(o))
{
lock (LookupPadLockByID(object.ID)
{
if (ReadyForUpdate(o))
{
PerformUpdate(object);
}
}
}
}
private static readonly object padlockLock = new object();
private static readonly Dictionary<int, string> padLocks = new Dictionary<int,string>();
private static object LookupPadLockByID(int uniqueID)
{
lock (padlockLock)
{
if (!padLocks.ContainsKey(uniqueID))
{
padLocks.Add(uniqueID, uniqueID + " is locked");
}
}
return padLocks[uniqueID];
}
4 个解决方案
#1
Well, you end up locking on a string, which isn't a good idea (although the concatenation means that interning shouldn't be a huge issue). What is a bigger issue is that:
好吧,你最终锁定了一个字符串,这不是一个好主意(虽然连接意味着实习不应该是一个大问题)。更大的问题是:
- you don't seem to remove the locks from
padLocks
- is that an issue? - you access the dictionary outside the
padlockLock
; thereturn
should be inside thelock
你似乎没有从padLocks中删除锁 - 这是一个问题吗?
你访问padlockLock之外的字典;返回应该在锁内
For this second, this would be simpler:
对于这一秒,这将更简单:
object itemLock;
if (!padLocks.TryGetValue(uniqueID, out itemLock)) {
itemLock = new object();
padLocks.Add(uniqueID, itemLock);
}
return itemLock;
If this code is fairly local (i.e. your objects haven't escaped yet), you might simply lock
the record itself? A lot simpler...
如果此代码是相当本地的(即您的对象尚未转义),您可能只是锁定记录本身?简单得多......
#2
Locking on a string is not a good idea. I suggest two alternatives:
锁定字符串不是一个好主意。我建议两种选择:
- Use a
Dictionary<int,object>
as padLocks' type, and put anew object();
as the value. - Create a class that simply holds the id; this would be better for readability if you ever want to look at your LockPad class while debugging.
使用Dictionary
创建一个只包含id的类;如果您想在调试时查看LockPad类,那么这对于可读性会更好。
LockPad class:
class LockPad {
public int Id { get; private set; }
public LockPad(int id) {
this.Id = id;
}
public override string ToString() {
return "lock of " + id.ToString();
}
}
Then, lock on that class.
然后,锁定该类。
#3
I think you are over engineering. If you only need to protect your DB entities (which I assume is represented by "object" in your code, which I will change to "entity"), you can just use it as your lock. Any reference object can be used as a lock:
我觉得你过度工程了。如果您只需要保护您的数据库实体(我假设在您的代码中由“对象”表示,我将更改为“实体”),您可以将其用作锁定。任何引用对象都可以用作锁:
public static func(CustomObject o)
{
if (ReadyForUpdate(o))
{
lock (entity)
{
if (ReadyForUpdate(o))
{
PerformUpdate(entity);
}
}
}
}
#4
If you're using a standard Database of any type, I would suggest dumping these client-side locks entirely in favor of transactions and table/row locks.
如果您使用的是任何类型的标准数据库,我建议完全转储这些客户端锁,以支持事务和表/行锁。
#1
Well, you end up locking on a string, which isn't a good idea (although the concatenation means that interning shouldn't be a huge issue). What is a bigger issue is that:
好吧,你最终锁定了一个字符串,这不是一个好主意(虽然连接意味着实习不应该是一个大问题)。更大的问题是:
- you don't seem to remove the locks from
padLocks
- is that an issue? - you access the dictionary outside the
padlockLock
; thereturn
should be inside thelock
你似乎没有从padLocks中删除锁 - 这是一个问题吗?
你访问padlockLock之外的字典;返回应该在锁内
For this second, this would be simpler:
对于这一秒,这将更简单:
object itemLock;
if (!padLocks.TryGetValue(uniqueID, out itemLock)) {
itemLock = new object();
padLocks.Add(uniqueID, itemLock);
}
return itemLock;
If this code is fairly local (i.e. your objects haven't escaped yet), you might simply lock
the record itself? A lot simpler...
如果此代码是相当本地的(即您的对象尚未转义),您可能只是锁定记录本身?简单得多......
#2
Locking on a string is not a good idea. I suggest two alternatives:
锁定字符串不是一个好主意。我建议两种选择:
- Use a
Dictionary<int,object>
as padLocks' type, and put anew object();
as the value. - Create a class that simply holds the id; this would be better for readability if you ever want to look at your LockPad class while debugging.
使用Dictionary
创建一个只包含id的类;如果您想在调试时查看LockPad类,那么这对于可读性会更好。
LockPad class:
class LockPad {
public int Id { get; private set; }
public LockPad(int id) {
this.Id = id;
}
public override string ToString() {
return "lock of " + id.ToString();
}
}
Then, lock on that class.
然后,锁定该类。
#3
I think you are over engineering. If you only need to protect your DB entities (which I assume is represented by "object" in your code, which I will change to "entity"), you can just use it as your lock. Any reference object can be used as a lock:
我觉得你过度工程了。如果您只需要保护您的数据库实体(我假设在您的代码中由“对象”表示,我将更改为“实体”),您可以将其用作锁定。任何引用对象都可以用作锁:
public static func(CustomObject o)
{
if (ReadyForUpdate(o))
{
lock (entity)
{
if (ReadyForUpdate(o))
{
PerformUpdate(entity);
}
}
}
}
#4
If you're using a standard Database of any type, I would suggest dumping these client-side locks entirely in favor of transactions and table/row locks.
如果您使用的是任何类型的标准数据库,我建议完全转储这些客户端锁,以支持事务和表/行锁。