任务中的领域异步使用

时间:2016-09-07 11:47:05

标签: c# xamarin realm

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

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

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

假设我们希望在启动Web请求的异步任务函数的上下文中保留在后台线程上。

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

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

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

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

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

编辑以下链接的异步示例回答了这个问题,任何进程占用了大量的cpu资源。那么人们会假设基本的Realm Write事务,例如管理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项目

1 个答案:

答案 0 :(得分:0)

我最近在自己的应用程序中遇到了此问题,但在StackOverflow上找不到很好的答案,所以我将分享我学到的知识。

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

如果只想在不一定占用大量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。如果您不能使用C#8.0,只需将它替换为using块:

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

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

相关问题