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的最佳实践是什么?只是使用同步版本?
在同步与异步和单个与并发之间有很大的区别,并且它们都有4种组合。
在单个异步情况下,您最多使用单个线程访问DB,但在整个操作中不需要是同一个线程,当您不需要线程时(当您等待IO
操作完成时),您根本不需要任何线程。
限制async
使用的最基本方法是将SemaphoreSlim
与initialCount = 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();
}
}