【问题标题】:C# Database call inside parallel loop并行循环内的 C# 数据库调用
【发布时间】:2017-10-19 08:48:49
【问题描述】:

我遇到了一段代码,其中我在 Parallel Loop 中看到了一些数据库调用。所以,我想到的问题是数据库调用是线程安全的,因为并行循环在多个线程中执行。

这是供您查看的一小段代码:

Parallel.ForEach(list, item =>
{
    //this function update the user status by connecting with database
    _IUserRepository.UpdateUserStatus(item.UserId, item.status);
});

每个线程是否并行循环,等待用户状态更新?

如果我们在以下列表中有记录会发生什么:

UserId, Status
1,0
1,1
1,0
1,1
  • id=1 的用户的最终状态是什么?
  • 这里是否存在死锁或竞争条件的可能性?

谢谢!

【问题讨论】:

  • 未知代码的线程安全是不可能的。 性能 虽然可能会受到很大影响,因为多个连接竞争相同的资源。如果您有性能问题,问题出在代码本身,不会随着并行化而改善。
  • 例如,如果您只执行单行更新,那么每次更新所花费的时间几乎有 80% 是网络流量。如果将 100 个更新一起批处理,或者将值作为表值参数传递,则可以将性能提高近 80 倍。更好的是,使用 SqlBulkCopy 将更改推送到临时表并在服务器上执行单个 UPDATE。 SqlBulkCopy 使用最少的日志记录和锁定 - 它不是记录每一行,而是记录整个页面。使用临时表,您也不会遇到任何锁定问题。
  • 更多普通问题 - 如果 UserID 不是索引的第一列,则每次 UPDATE 都会导致全表扫描。索引它和性能将增加几个数量级
  • @PanagiotisKanavos,感谢您提供详细信息 cmets。这对我很有帮助。
  • 为什么用“sql-server”标记?

标签: c# sql-server multithreading parallel-processing


【解决方案1】:

我们无法判断这段代码是否“线程安全”,因为它取决于_IUserRepository.UpdateUserStatus 是否是线程安全的,而且我们没有它的源代码。假设它是线程安全的,在您的情况下用户的最终状态仍然不确定:无论UPDATE 语句最后命中数据库,都将获胜并覆盖给定用户的所有先前更改。至于死锁 - 我看不到任何可以在这里死锁的东西。也就是说 - 在此类列表中为具有不同状态的同一用户进行多次更新已经没有多大意义。对于任何给定用户,只有一个条目应该在这样的列表中(因此它应该是由用户 ID 键入的 Dictionary)。

【讨论】:

    【解决方案2】:

    每个线程是否并行循环,等待用户状态更新?

    我猜答案取决于。取决于您的数据库事务级别。级别越高,线程在更新数据库中的相同记录时必须相互等待的机会就越大。如果列表是不同用户的列表,我认为不应该是这种情况。

    id=1 的用户的最终状态是什么?

    这无法确定。对于每次运行,您最终都会得到不同的答案。但我不认为这段代码是为这种情况编写的,而是为你有一个包含不同用户的列表的情况编写的。否则代码没有意义。

    这里有死锁或竞争条件的可能性吗?

    没有死锁,没有竞争条件,只有当您考虑上面刚刚给出的示例时。但同样,如前所述,我认为此代码适用于具有不同用户的列表。

    【讨论】:

      猜你喜欢
      • 2023-03-24
      • 2020-07-13
      • 1970-01-01
      • 1970-01-01
      • 2017-12-25
      • 2022-03-11
      • 1970-01-01
      • 2017-09-08
      • 2017-08-05
      相关资源
      最近更新 更多