1

我有以下代码可以完成一些数据库工作:

[WebMethod]
public void FastBulkAdd(int addmax){
Users[] uploaders = db.Users.Take(addmax).ToArray();

Parallel.ForEach(uploaders, item =>
{
    Account account;
    lock (this)
    {
        account = item.Account;
    }
}

每个用户都有 1 个帐户,DB 通过外键在另一个表中引用该帐户(我确定每个用户都有 1 个帐户)。我必须锁定那段代码,因为多线程数据库连接会产生错误。当我将此设置 addmax 设置为 1(允许 1 个线程执行)时,它工作得很好,但是如果 addmax 大于 1 并且执行了多个线程,则 account 将始终为 null,这会在稍后生成异常。这几乎就像锁被跳过了。

更新:我不相信帐户总是空的,所以我做了以下事情:

int tries = 0;
while (account == null && tries < 100)
{
    lock (this)
    {
        account = item.Account;
    }
    tries++;
}

它奏效了。不是一个非常整洁的解决方案。我想知道问题的原因,以便将来避免这种设计危险。

4

3 回答 3

2

item.Account进行数据库查找,对吗?您能否一次将其替换为所有上传者帐户的批量选择?这样,您只需对数据库进行一次选择,然后对数据库进行一次批量更新,并且您不关心同步的数据库访问(无论如何,每次额外的点击都会花费大量时间)

于 2013-02-09T07:49:37.837 回答
0

而不是锁定this创建一个private static object并锁定它;你可以参考这个线程

此外,您需要验证 item.Account 不为空。另一个问题是,即使您锁定了Account,似乎您稍后也在此代码中使用它。即使您正在锁定,这似乎也不正确,然后它可能会在稍后将其保存到数据库的部分中更改,因为它未锁定。请参考以下示例;

lock (this)
{
    account = item.Account;
}
DoSomeDatabaseOperation(account); // the account may change here when another thread is also operating.

您也可以调试并行操作;请参阅此 msdn 页面

于 2013-02-09T07:35:34.033 回答
0

你可以使用 [MethodImpl(MethodImplOptions.Synchronized)] 例如

  [MethodImpl(MethodImplOptions.Synchronized)]
    [WebMethod]
    public void FastBulkAdd(int addmax)
    {
    }

有关更多详细信息,请参阅以下链接。 http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimploptions.aspx

于 2013-02-09T07:59:38.083 回答