加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby-on-rails – 在同一个数据库上工作的多个工作线程 – 如何

发布时间:2020-12-17 02:35:51 所属栏目:百科 来源:网络整理
导读:我有一个数据库,其中包含需要操作的行列表.它看起来像这样: id remaining delivered locked============================================1 10 24 f 2 6 0 f3 0 14 f 我在Ruby中使用DataMapper,但实际上我认为这是一个通用的编程问题,并不是我所使用的具体
我有一个数据库,其中包含需要操作的行列表.它看起来像这样:

id       remaining        delivered   locked
============================================
1        10               24          f 
2        6                0           f
3        0                14          f

我在Ruby中使用DataMapper,但实际上我认为这是一个通用的编程问题,并不是我所使用的具体实现所特有的…

我正在创建一堆工作线程,它们执行类似这样的操作(伪ruby代码):

while true do
  t = any_row_in_database_where_remaining_greater_than_zero_and_unlocked
  t.lock   # update database to set locked = true
  t.do_some_stuff
  t.delivered += 1
  t.remaining -= 1
  t.unlock
end

当然,问题是,这些线程相互竞争,整个事情并不是真正的线程安全. while循环中的第一行可以很容易地在多个线程中拉出相同的行,然后才有机会被锁定.

我需要确保一个线程同时只在一行上工作.

做这个的最好方式是什么?

解决方法

关键步骤是从数据库中选择未锁定的行并将其标记为已锁定.如果你能安全地做到这一点,那么其他一切都会好的.

我所知道的两种方式可以使这种安全是悲观和乐观的锁定.在并发性方面,它们都依赖于您的数据库作为最终保证.

悲观锁定

悲观锁定意味着当您选择要使用的行时,先获取锁定,以便其他任何人都无法读取它们.
就像是

SELECT * from some_table WHERE ... FOR UPDATE

与mysql和postgres(以及可能的其他人)一起工作,并将阻止与数据库的任何其他连接读取返回给你的行(锁的粒度取决于所使用的引擎,索引等 – 检查数据库的文档).它被称为悲观,因为您假设将发生并发问题并预防性地获取锁.它确实意味着即使在没有必要的情况下您也要承担锁定的成本,并且可能会降低您的并发性,具体取决于您拥有的锁的粒度.

乐观锁定

乐观锁定是指一种技术,您不需要悲观锁定的负担,因为大多数时候不会有并发更新(如果您在读取行时更新行设置锁定标志为true,窗口相对较小). AFAIK只适用于一次更新一行

首先在表中添加一个整数列lock_version.每当您更新表时,将lock_version与您正在进行的其他更新一起递增1.假设当前的lock_version为3.更新时,将更新查询更改为

update some_table set ... where id=12345 and lock_version = 3

并检查更新的行数(db驱动程序返回此值).如果这更新1行,那么你知道一切都好.如果此更新为0行,则删除所需的行或其锁定版本已更改,因此您将返回到流程中的步骤1并搜索要处理的新行.

我不是datamapper用户,所以我不知道它/ plugins是否为这些方法提供支持. Active Record支持两者,因此如果数据映射器不支持,您可以在那里寻找灵感.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读