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

问题描述 投票:0回答:2

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

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

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

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

我尝试将异步与同步代码一起使用 - 并且该代码正确地给了我编译错误以避免死锁。
为什么我不能在锁定语句体内使用“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 使用。

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

c# multithreading sqlite locking async-await
2个回答
7
投票

同步与异步单一与并发之间存在很大差异,并且它们共有 4 种组合。

single asynchronous 情况下,您最多使用单个线程访问数据库,但在整个操作过程中不需要是同一个线程,并且当您不需要线程时(当您等待时)为了完成

IO
操作)您根本不需要任何线程。

async
的使用限制为一次单个操作的最基本方法是将
SemaphoreSlim
initialCount = 1
一起使用。更好的方法是使用
AsyncLock
构建异步协调原语,第 6 部分:AsyncLock,作者: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


4
投票

您的数据库不接受多次访问(插入、更新等)这一事实并不意味着对其进行工作的单个线程必须使用阻塞 api 来执行此操作。

如果您不必进行跨进程锁定,您可以在异步方法中使用

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();
   }
}
© www.soinside.com 2019 - 2024. All rights reserved.