TinyDb 的集合接口提供了完整异步版本:InsertAsync / UpdateAsync / DeleteAsync / FindAsync / UpsertAsync。
这篇文章给出在 Web API、后台任务中可直接复用的写法。
1. 为什么要用异步
避免同步 I/O 阻塞线程池。
提升高并发请求下的吞吐。
更容易接入超时与取消控制。
2. 基础异步 CRUD 示例
using var db = new TinyDb.Core.TinyDbEngine("async.db");
var tasks = db.GetCollection<TodoTask>();
var task = new TodoTask
{
Title = "完成接口联调",
Priority = TaskPriority.High,
Status = TodoStatus.Pending
};
// C
var id = await tasks.InsertAsync(task);
// R
var loaded = await tasks.FindByIdAsync(id);
// U
if (loaded != null)
{
loaded.Status = TodoStatus.InProgress;
await tasks.UpdateAsync(loaded);
}
// D
await tasks.DeleteAsync(id);3. 批量异步写入
var batch = Enumerable.Range(1, 1000)
.Select(i => new TodoTask
{
Title = $"任务-{i}",
Priority = (TaskPriority)(i % 3),
Status = TodoStatus.Pending
})
.ToList();
var inserted = await tasks.InsertAsync(batch);
Console.WriteLine($"批量异步插入: {inserted}");4. 取消令牌(必须掌握)
4.1 外部请求驱动取消
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
try
{
var result = await tasks.FindAsync(
x => x.Status == TodoStatus.Pending,
cancellationToken: cts.Token);
Console.WriteLine($"查询完成: {result.Count}");
}
catch (OperationCanceledException)
{
Console.WriteLine("查询被取消(超时或外部取消)");
}4.2 显式取消
using var cts = new CancellationTokenSource();
var running = tasks.InsertAsync(new TodoTask { Title = "长任务" }, cts.Token);
cts.Cancel();
try
{
await running;
}
catch (OperationCanceledException)
{
Console.WriteLine("写入被主动取消");
}5. 并发执行建议
5.1 正确方式:有限并发
var semaphore = new SemaphoreSlim(8); // 并发上限
var source = Enumerable.Range(1, 2000);
var jobs = source.Select(async i =>
{
await semaphore.WaitAsync();
try
{
await tasks.InsertAsync(new TodoTask { Title = $"并发任务-{i}" });
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(jobs);5.2 不推荐:无上限 Task.WhenAll 扔 10w 个任务
会造成:
内存膨胀。
线程池调度压力增大。
上下文切换过多导致抖动。
6. Web API 中的典型封装
public sealed class TodoService
{
private readonly TinyDb.Collections.ITinyCollection<TodoTask> _tasks;
public TodoService(TinyDb.Core.TinyDbEngine db)
{
_tasks = db.GetCollection<TodoTask>();
}
public async Task<ObjectId> CreateAsync(string title, CancellationToken ct)
{
var task = new TodoTask
{
Title = title,
Priority = TaskPriority.Medium,
Status = TodoStatus.Pending
};
var id = await _tasks.InsertAsync(task, ct);
return id.As<ObjectId>();
}
public Task<List<TodoTask>> QueryPendingAsync(int page, int pageSize, CancellationToken ct)
{
return _tasks.FindAsync(
x => x.Status == TodoStatus.Pending,
(page - 1) * pageSize,
pageSize,
ct);
}
}7. 小结
异步接口是服务端高并发的默认选项。
永远把
CancellationToken贯通到存储层。并发写入要有上限,不要无限制扔任务。
下一篇进入安全主题:密码保护和安全访问策略。
附:示例实体
using TinyDb.Attributes;
using TinyDb.Bson;
[Entity("todo_tasks")]
public partial class TodoTask
{
[Id]
public ObjectId Id { get; set; } = ObjectId.NewObjectId();
public string Title { get; set; } = string.Empty;
public TaskPriority Priority { get; set; } = TaskPriority.Medium;
public TodoStatus Status { get; set; } = TodoStatus.Pending;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
public enum TaskPriority { Low, Medium, High }
public enum TodoStatus { Pending, InProgress, Completed, Cancelled }
发表评论