【问题标题】:Multithreading in C# sqliteC# sqlite 中的多线程
【发布时间】:2013-11-15 12:29:35
【问题描述】:

我在 C# wpf 应用程序中编程并使用 Sqlite 数据库。假设我有 25 个辅助线程都在等待对数据库执行插入操作。现在主线程对数据库执行选择操作。我可能错了,但是这个主线程会等待一段时间。我如何保证。所以我将数据库锁定在我的日志文件中。我如何确保主线程获得最高优先级,以便我的 UI 不会被阻塞。我正在使用 DBContext 对象来执行数据库操作。?

【问题讨论】:

  • 向我们展示一些代码,并告诉我们为什么它不能正常工作。 清楚地说明您想要什么,以及您想从我们这里得到什么。
  • 我希望主线程获得最高优先级,其他线程在执行数据库操作时等待,这样我的 UI 就不会被阻塞。当我在我的 UI 上执行操作时,我得到了数据库锁定异常

标签: c# multithreading sqlite


【解决方案1】:

巧妙地使用ReaderWriterLockSlim 肯定会帮助您提高性能。

    private ReaderWriterLockSlim _readerWriterLock = new ReaderWriterLockSlim();

    private DataTable RunSelectSQL(string Sql)
    {
        DataTable selectDataTable = null;
        try
        {
            _readerWriterLock.EnterReadLock();                
            //Function to acess your database and return the selected results
        }
        finally
        {
            _readerWriterLock.ExitReadLock();
        }
        return selectDataTable;
    }

    private DataTable RunInsertSQL(string Sql)
    {
        DataTable selectDataTable = null;
        bool isbreaked = false;
        try
        {
            _readerWriterLock.EnterWriteLock();
            if (_readerWriterLock.WaitingReadCount > 0)
            {
                isbreaked = true;
            }
            else
            {
                //Function to insert data in your database
            }
        }
        finally
        {
            _readerWriterLock.ExitWriteLock();
        }

        if (isbreaked)
        {
            Thread.Sleep(10);
            return RunInsertSQL(Sql);
        }
        return selectDataTable;
    }

试试吧,它会提高你的响应能力,并且你有Select 查询可以触发,它比Insert SQL 具有更高的优先级。

请注意,如果某些插入已在运行,则 Select 至少会等待该插入完成。 此代码将始终优先于SELECT 而不是INSERT

还有一点,千万不要像从数据库中选择那样在主线程上执行长时间的操作,而是在后台执行操作然后使用主线程在 UI 上反映最新结果。这将确保您的 UI 永远不会冻结。

编辑如果连续的SELECT 查询被无间隔地触发,则可能会出现所有INSERT 都在等待的饥饿情况。
但我相信在您的情况下,这不会发生,因为 UI 不会总是令人耳目一新,如此频繁地获取最新更改,而两者之间没有任何时间片。

【讨论】:

  • 仍然不行,主线程仍然被阻塞了很长一段时间,数据库中最多插入了 25 行,所以我想,主线程不应该等待相当多的时间
  • 线程优先级与数据库访问无关。序列化访问将始终使用互斥锁排队您的事务。
  • @dbw 替换某种优先级队列的好方法
  • 如果你有一个insert 正在进行中并且你开始一个selectselect 仍然需要等待。 readwritterlock 所做的只是使许多读取可以并发,但是当写入锁有帮助时,一切都被阻止了。
  • @Gusdor 这一点在我之前的编辑中已经提到过,但在最后一次编辑中我偶然删除了它
【解决方案2】:

您在什么模式下运行数据库?

SQLite 支持三种不同的线程模式:

  1. 单线程。在这种模式下,所有互斥锁都被禁用,SQLite 不能安全地同时在多个线程中使用。
  2. 多线程。在这种模式下,SQLite 可以被多个线程安全使用,前提是不使用单个数据库连接 同时在两个或多个线程中。
  3. 已序列化。在序列化模式下,SQLite 可以不受限制地被多个线程安全使用。

默认模式为序列化。

http://www.sqlite.org/threadsafe.html

看起来多线程是你想要的。序列化数据库访问很慢

【讨论】:

  • 会检查它,但为什么整个数据库被锁定,我在不同的表中执行 select 语句并在不同的表上插入,两个表完全独立于其他表。所以表锁定有意义,但数据库锁定没有意义。有没有办法改变这个设置?
  • @yshooooo 我链接的文档描述了如何更改操作模式。您如何实现这在很大程度上取决于您如何创建连接。默认模式(序列化)为每个事务完全锁定数据库。无论使用如何,这都提供了完全的线程安全性。
  • 我在 IIS7 上运行的网站遇到问题。多个请求同时进入,我收到“数据库已锁定”错误。我看不到如何设置多线程模式。该文档针对 C/C++ 进行了描述,但在 C# 中没有。
  • @pwrgreg007 我总是建议为 Web 应用程序运行数据库服务器。 SQLite 用于嵌入式部署。这可能不会立即有帮助,但从长远来看会解决问题。
  • 我发布这个是希望有人会觉得它有用。请注意,我们仅将此本地/后端/嵌入式数据库用于状态信息。我们还将 SQL Server 用于主数据库,但我们希望站点本地的状态信息,而不必担心网络问题。该站点与设备(实际上是时钟)而不是人对话,我们需要一种方法来跟踪事件,例如发送生物特征信息。该数据库已增长到超过 250MB,因此该大小导致 SQLite 大幅减速。当我清除了一张包含过去状态信息的大表并对其进行清理时,“数据库锁定”错误消失了。
【解决方案3】:

A 在我的多线程缓存子系统中遇到了完全相同的问题 看起来它只是“System.Data.SQLite”库问题

添加这个(使用反射器找到)

"...;Version=3;Pooling=True;Max Pool Size=100;"

到连接字符串解决了这个问题。

【讨论】:

    猜你喜欢
    • 2015-11-01
    • 1970-01-01
    • 2018-05-14
    • 1970-01-01
    • 2013-12-06
    • 2012-02-15
    • 1970-01-01
    • 2012-05-29
    • 1970-01-01
    相关资源
    最近更新 更多