sqlite在锁或异步上的正确用法是什么?

本文关键字:用法 是什么 异步 sqlite | 更新日期: 2023-09-27 18:08:15

我们正在使用Xamarin编写android和ios的SQLite c#代码。然而,关于如何使用sqlite,我似乎有一个概念上的误解:

Android上SQLite的最佳实践是什么?

根据stackoverflow的回答,它说-一个helper和一个db连接。使用锁来确保在任何时候只有一个线程在访问sqlite数据库。

我的问题是——如果是这样的话——异步的用途是什么?

我尝试在同步代码中使用async——代码正确地给了我编译错误,以避免死锁。
为什么我不能使用'await'在锁语句体中的操作符?

    public async Task InsertAsync<T> (T item){
        lock (mutex) {
            await asyncConnection.InsertAsync (item);
        }
    }
    public async Task InsertOrUpdateAsync<T> (T item){
        lock (mutex) {
            int count = await asyncConnection.UpdateAsync (item);
            if (0 == count) {
                await asyncConnection.InsertAsync (item);
            }
        }
    }

失败。然而,如果我要使用锁来确保我一次使用一个连接一个线程作为sqlite的最佳实践,为什么有一个异步sqlite库呢?

为什么有些线程在网络上提倡异步sqlite的使用?

android和iphone上sqlite的最佳实践是什么?只是使用同步版本?

sqlite在锁或异步上的正确用法是什么?

同步与异步单个与并发之间有很大的区别,并且它们都有4种组合。

单个异步情况下,您最多使用单个线程访问DB,但在整个操作中不需要是同一个线程,当您不需要线程时(当您等待IO操作完成时),您根本不需要任何线程。

限制async使用的最基本方法是将SemaphoreSliminitialCount = 1一起使用。一个更好的方法是使用AsyncLock(构建异步协调原语,第6部分:AsyncLock by Stephen Toub):

private readonly AsyncLock _lock = new AsyncLock(); 
public async Task InsertAsync<T> (T item)
{
    using(await _lock.LockAsync())
    {
        await asyncConnection.InsertAsync (item);
    }
}
public async Task InsertOrUpdateAsync<T> (T item)
{
    using(await _lock.LockAsync())
    {
        if (0 == await asyncConnection.UpdateAsync (item))
        {
            await asyncConnection.InsertAsync (item);
        }
    }
}

注意:我的AsyncLock的实现

你的数据库不接受多次访问(插入,更新等)的事实并不意味着对它工作的单个线程必须使用阻塞api。

如果你不需要跨进程锁定,你可以在async方法中使用SemaphoreSlim.WaitAsync而不是Mutex来异步等待锁:

private readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(initialCount: 1);
public async Task InsertAsync<T>(T item)
{
   await semaphoreSlim.WaitAsync();
   try
   {
      await asyncConnection.InsertAsync(item);
   }
   finally
   { 
      semaphoreSlim.Release();
   }
}
public async Task InsertOrUpdateAsync<T>(T item)
{
   await semaphoreSlim.WaitAsync();
   try
   {      
      int count = await asyncConnection.UpdateAsync(item);
      if (0 == count) 
      {
         await asyncConnection.InsertAsync(item);
      }
   }
   finally
   {
      semaphoreSlim.Release();
   }
}