【问题标题】:Multi-threading with Sequel gemSequel gem 的多线程
【发布时间】:2017-08-26 01:38:42
【问题描述】:

我有一个程序,它使用 Sequel gem(它基本上是一个价格聚合器)将 JSON 请求数据存储到 Postgres 数据库中。但是,正在使用线程从多个位置快速提取数据。

一旦我得到适当的数据,我目前就有一个 mutex.synchronize 与以下内容:

dbItem = Item.where(:sku => sku).first
dbItem = Item.create(:sku => sku, :name => itemName) if dbItem == nil
dbPrice = Price.create(:price => foundPrice, :quantity => quantity)
dbItem.add_price(dbPrice)
store.add_price(dbPrice)

如果我在没有互斥锁的情况下运行它,我会遇到线程问题 - 例如,代码将尝试在数据库中创建一个项目,但该项目刚刚由另一个线程创建。

但是,使用互斥锁后,这段代码的速度会明显变慢 - 我发现我的程序花费了大约四六倍的时间。

老实说,我对整个数据库都是新手,所以我只是想找出处理线程的最佳方法。我做错了吗? Sequel 的文档实际上声明了几乎所有线程安全的... 除了 对于模型实例,我相信我的项目情况属于这种情况。它说我应该先冻结模型,但我不知道如何在这里应用它..

【问题讨论】:

  • 我没有你的答案,但是,将 ruby​​ 放在地图上的一件事是 rails 和 activerecord。我觉得 activerecord 可能会更好地解决您的线程问题,并且它有足够的用途,它的性能可能相当不错。一旦你把它的 ORM 搞定,使用起来会很有趣。 (guides.rubyonrails.org/active_record_basics.html)

标签: ruby postgresql sequel


【解决方案1】:

您不是在处理共享模型实例,这不是线程安全问题,而是竞争条件(它会使用多个进程发生,而不仅仅是多个线程)。您需要使用特定于数据库的支持以无竞争条件的方式处理此问题。在 PostgreSQL 9.5+ 上,您需要使用 Dataset#insert_conflict。

续集文档:http://sequel.jeremyevans.net/rdoc-adapters/classes/Sequel/Postgres/DatasetMethods.html#method-i-insert_conflict

PostgreSQL 文档:https://www.postgresql.org/docs/9.5/static/sql-insert.html

【讨论】:

  • 啊,很有趣。这更有意义。在更新另一个线程可能同时更新的条目的情况下,这是否是自动线程安全的?这是我应该冻结条目的情况吗?
  • 正如我所提到的,这不是线程安全问题,因此冻结任何内容都无济于事。问题是访问数据库方面的竞争条件,因此您必须使用特定于数据库的方法来处理此问题。它通常被称为 upsert,因为它的作用是:插入,如果违反唯一约束,则更新现有行。
猜你喜欢
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 2018-02-27
  • 1970-01-01
  • 2017-06-01
  • 2020-03-03
  • 1970-01-01
  • 2017-06-16
相关资源
最近更新 更多