【问题标题】:best way to write data to a sqlite from multiple threads从多个线程将数据写入sqlite的最佳方法
【发布时间】:2017-02-08 15:47:31
【问题描述】:

我正在创建一个监控应用程序。我想从所有服务器读取查询并将其存储在 sqlite 文件中。在需要时显示它。我正在使用 c++ 编写此应用程序 - 从多个服务器获取数据并将其存储到单个 sqlite 数据库。我正在使用单独的线程从多个服务器获取数据。如果我直接获取数据并将数据写入sqlite,那么它可能会锁定sqlite文件,因为100个线程将同时写入。 从多个线程将数据写入sqlite的最佳方法是什么?

【问题讨论】:

  • The X-Y solution:考虑使用selectepoll、重叠 IO 或您的操作系统最支持的任何 IO 多路复用器来减少线程数。
  • 编辑了我的问题。我无法减少线程数,这取决于连接的服务器数量。
  • 对,但是使用多路复用器,一个线程可以管理多个服务器。
  • 为了强化 user4581301 的评论,请记住来自多个服务器的所有网络流量都通过您计算机上的单个网络接口。看起来您正在多个线程中同时访问多个服务器,但由于这一切都发生在您的网络上,因此访问是序列化的。所以一个线程可以像处理多个线程一样容易地处理多个服务器连接。
  • 我还强烈建议您重新考虑 user4581301 的评论。谷歌“c10k”问题。您可能在滥用线程。

标签: c++ multithreading sqlite


【解决方案1】:

如果您无法控制同时写入操作的数量,我认为使用 sqlite 没有更好的方法。

SQLite 不是为您的用例而设计的。考虑切换到客户端/服务器 RDBMS。这也是 SQLite 的建议:

https://www.sqlite.org/whentouse.html

客户端/服务器 RDBMS 可能工作得更好的情况

客户端/服务器应用程序

如果有许多客户端程序通过网络向同一个数据库发送 SQL,则使用客户端/服务器数据库引擎而不是 SQLite。 SQLite 将在网络文件系统上工作,但由于 与大多数网络文件系统相关的延迟,性能不会 很棒。此外,文件锁定逻辑在许多网络文件系统中是错误的 实现(在 Unix 和 Windows 上)。如果文件锁定不 正常工作,两个或多个客户端可能会尝试修改同一部分 同一个数据库,导致损坏。 因为这个问题是由底层文件系统中的错误引起的 实现,SQLite 无法阻止它。

一个好的经验法则是避免在直接访问同一个数据库的情况下使用 SQLite(没有干预 应用程序服务器),并同时从多台计算机通过 网络。

(...)

高并发

SQLite 支持无限数量的同时读取器,但它在任何时刻只允许一个写入器。对于很多 情况下,这不是问题。作家排队。每个应用程序 它的数据库是否快速工作并继续前进,并且没有锁定持续 超过几十毫秒。但是有一些应用 需要更多的并发性,并且这些应用程序可能需要寻求 不同的解决方案。

【讨论】:

    【解决方案2】:

    您可以使用 RabbitMQ 或 Redis 等消息队列来解决此类问题

    1. 将数据发送到队列,擅长异步插入
    2. 创建一个工作线程,它将从队列中获取新消息
    3. 使用该工作线程向 SQLite 插入新消息

    在这种架构下,只有一个工作线程会写入数据库,不会出现锁定问题,因为 SQLite 可以在“一写多读”模式下工作

    【讨论】:

      【解决方案3】:

      所有线程只使用一个 sqlite 数据库连接,打开时设置了标志 SQLITE_OPEN_FULLMUTEX。 然后数据库将序列化来自所有线程的写入,并且不会有锁定。 但是您需要调整您的数据库和应用程序设计,以便编写查询运行得足够快,这需要多少。

      【讨论】:

      • FULLMUTEX 是加锁的,不是没有加锁的。它也只影响连接对象,无论如何你都不应该在线程之间共享它,因为各种原因(每个线程都应该有自己的连接)。
      • 对于最后的数据库写入操作,您总是锁定表行和/或表页,这可能导致死锁。始终建议只有一个数据库写入线程/进程或使用 FULLMUTEX。额外的细化可以是写入相同表的线程应该具有锁定并且写入不同表的线程没有。对于读取操作,不需要序列化,它们可以并行运行。
      • SQLite 对整个数据库使用单个锁。没有陷入僵局的可能。同样,FULLMUTEX 保护 connection 对象,它不应该在线程之间共享,因为它使使用事务变得不可能。
      • 您与自己和所提出的问题相矛盾。问题是:“从多个线程将数据写入 sqlite 的最佳方法是什么?”因此,您的评论“连接对象,不应在线程之间共享”与所要求的相矛盾。这里需要从多个线程进行访问,唯一安全的方法是使用互斥锁。
      • "每个线程应该有自己的连接" 您可以有多个连接到同一个数据库。连接将处理围绕事务的锁定。
      猜你喜欢
      • 1970-01-01
      • 2015-10-26
      • 1970-01-01
      • 1970-01-01
      • 2012-08-24
      • 2013-12-24
      • 1970-01-01
      • 1970-01-01
      • 2013-03-20
      相关资源
      最近更新 更多