【问题标题】:Realm async usage in Tasks任务中的领域异步使用
【发布时间】:2016-09-07 11:47:05
【问题描述】:

我试图更好地理解如何在异步场景中使用 Realm。据我所知,Realm 实例只能访问它创建的线程上的对象。因此,要进行异步事务,我需要使用 GetInstance("SomeRealmFile"); 的领域的新实例。

有一个名为Task WriteAsync(Action<Realm> action) 的函数可以在工作(后台)线程上执行写事务。

这是一个示例场景。该应用程序需要发出网络请求。所以它运行一个异步任务函数来访问网络并获取一些数据。请求成功返回,现在应用程序希望将该数据解析为 Realm 对象,并使用 Realm.Manage<T>(T Obj) 将其保存到数据库中。请注意,整个场景假设我们已经在 UI 主线程上创建了 Realm 数据库。

假设此时我们想留在后台线程,在启动 Web 请求的异步任务函数的上下文中。

所以现在我们处于通过var results = await WebFetch(); 获得 Web 请求(数据)结果的情况,可能使用类似 TaskCompletionSource 的东西,然后最终我们可以在工作线程上执行 Realm 写入事务。 我假设此时调用异步写入事务,我们需要获取 Realm 的新实例并将其传递给 WriteAsync() 函数。

这引发了另一个问题,假设在数据库写入事务之前,我们想要做一些查询并在我们写东西之前检查一些事情。如果我们在异步函数中执行这些查询会发生什么?因为我之前尝试过很多奇怪的事情,所以有时它会起作用,有时查询只是返回 null (当然取决于查询的类型)。在主线程上完美运行的查询。

编辑这可能是一个错误,异步函数中的查询非常不可靠。

所以为了清楚起见,我们仍然假设我们之前从异步任务(网络获取)返回,现在我们正在执行一些 Realm 查询,然后调用 Task WriteAsync(Action<Realm> action) 函数将数据写入数据库。这是正确的方法吗?对此进行一些澄清会很棒。

最后一点,异步写入事务是否必要?什么样的 Realm 场景(写入事务)可能会阻塞 UI 线程足够长的时间,以至于它需要并证明在工作线程上执行(仅从移动开发的角度来看)。

编辑下面链接的异步示例回答了这个问题,任何占用大量 cpu 资源的进程。所以有人会假设基本的领域写入事务,例如管理 50 个对象的列表不应该是异步的?

一个伪代码示例会很棒。

编辑 在我的脑海中添加了一个代码示例。

async Task RealmWritesAsync
{
    var result = await WebFetch();

    // Maybe do some queries here
    var realm = Realm.GetInstance("RealmFile");
    await realm.WriteAsync(realm =>
    {
          // Realm.Manage the results
    });
}

环境 = 带有使用 MvvmCross 的 PCL 的 Xamarin.iOS/Droid 项目

【问题讨论】:

  • Realm 没有异步 API 吗? github.com/realm/realm-dotnet/blob/master/Tests/…表示有异步吗?
  • 我在帖子中多次引用了 Realm 用于 Async 的函数。我不是在质疑它是否可以支持它,只是更多关于用例的问题。
  • 该链接很有用,但谢谢。
  • 我不知道Realm.NET的语法,但是如果你在后台线程,你一般应该打开一个Realm实例,同步执行写事务,然后关闭Realm实例。 Realm.NET 有类似的东西吗?
  • 是的,这就是我在其他帖子中读到的内容,同步执行写入位。因此,例如启动另一个同步任务,然后返回执行 Web 获取的异步任务。

标签: c# xamarin realm


【解决方案1】:

我最近在自己的应用程序中遇到了这个问题,但在 StackOverflow 上没有找到好的答案,所以我将分享我学到的东西。

Realm 类上的WriteAsync 函数仅适用于您需要在写入事务中执行大量 CPU 繁重工作的情况。传递给 lambda 的 Realm 实例是工作线程上的一个实例,必须使用该实例而不是原始的 Realm 实例,以便在该 lambda 内完成操作。

如果您只想在不一定占用大量 CPU 的写入事务中执行异步工作,则必须手动启动事务,然后在完成后提交。我写了一个扩展方法来简化这个,命名为WriteTask 以避免与现有的WriteAsync 函数冲突:

/// <summary>
/// Async-friendly version of Realm.Write, meaning the work function can return a task
/// which will be awaited in the scope of the transaction.
/// </summary>
public static async Task WriteTask(this Realm realm, Func<Task> workFunction)
{
    using var transaction = realm.BeginWrite();

    await workFunction();

    transaction.Commit();
}

请注意,这使用了 C# 8.0 using 声明语法。如果您不能使用 C# 8.0,只需将其替换为 using 块:

using (var transaction = realm.BeginWrite())
{
    await workFunction();
    transaction.Commit();
}

只要从主 (UI) 线程调用 .WriteTask 方法,并且在等待 lambda 内的任何 Tasks 时不使用 .ConfigureAwait(false),这将允许在写入内完成异步工作无需单独的Realm 实例即可进行交易。但是,请注意不要让多个并发异步操作尝试同时启动事务,因为这会引发异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-24
    相关资源
    最近更新 更多