1

也许我遗漏了一些东西,但是在从同一个对象的 Realm 并行读取和写入时,我得到了一些奇怪的结果。

我第一次遇到这个是在一个更大的项目中,但现在才设法在一个测试项目中重现它。

场景:创建一个RealmObject具有两个DateTimeOffset字段的对象,然后每分钟更新一次。另一个线程每 10 秒读取一次并输出值。

我将首先显示输出,因为它最相关。括号中的时间是记录输出的时间。剩下的是标识符(READER/WRITER),然后是RealmObject.

发生的情况是,在成功写入后,读取器读取旧值一段时间,然后读取新值,然后再次读取旧值。如果我重新启动应用程序,那么一切都会好起来的,当然,有一段时间。

//阅读器开始阅读。输出是正确的

[0:] (10:05:44.656) 读者:[{"LastSyncTime":"2016-07-17T22:04:45.384+00:00","LastChangeDate":"2016-07-17T22:09:45.384+ 00:00","IsManaged":true}] [0:] (10:05:54.656) 读者:[{"LastSyncTime":"2016-07-17T22:04:45.384+00:00","LastChangeDate" :"2016-07-17T22:09:45.384+00:00","IsManaged":true}] [0:] (10:06:04.657) 读者:[{"LastSyncTime":"2016-07-17T22: 04:45.384+00:00","LastChangeDate":"2016-07-17T22:09:45.384+00:00","IsManaged":true}]

//Writer进来并更新值。

[0:] (10:06:07.523) WRITER: {"LastSyncTime":"2016-07-17T22:06:07.521+00:00","LastChangeDate":"2016-07-17T22:11:07.523+00 :00","IsManaged":true}

//Reader 读取不正确(OLD)值一段时间

[0:] (10:06:14.661) 读者:> [{"LastSyncTime":"2016-07-17T22:04:45.384+00:00","LastChangeDate":"2016-07-17T22:09:45.384 +00:00","IsManaged":true}] [0:] (10:06:24.678) 读者:[{"LastSyncTime":"2016-07-17T22:04:45.384+00:00","LastChangeDate ":"2016-07-17T22:09:45.384+00:00","IsManaged":true}] [0:] (10:06:34.678) 读者: [{"LastSyncTime":"2016-07-17T22 :04:45.384+00:00","LastChangeDate":"2016-07-17T22:09:45.384+00:00","IsManaged":true}]

//Reader 突然读取到正确的值

[0:] (10:06:44.678) 读者:[{"LastSyncTime":"2016-07-17T22:06:07.521+00:00","LastChangeDate":"2016-07-17T22:11:07.523+ 00:00","IsManaged":true}]

//Reader 回退到以前的值 (????)

[0:] (10:06:54.678) 读者:[{"LastSyncTime":"2016-07-17T22:04:45.384+00:00","LastChangeDate":"2016-07-17T22:09:45.384+ 00:00","IsManaged":true}] [0:] (10:07:04.678) 读者:[{"LastSyncTime":"2016-07-17T22:04:45.384+00:00","LastChangeDate" :"2016-07-17T22:09:45.384+00:00","IsManaged":true}]

编码:

public class TimestampDataObject : RealmObject
{
    public DateTimeOffset LastSyncTime { get; set; }
    public DateTimeOffset? LastChangeDate { get; set; }
}

写作部分:

Observable.Interval(TimeSpan.FromMinutes(1)).Subscribe(async (v) =>
{
    await Realm.GetInstance().WriteAsync(r =>
    {
        var item = r.All<TimestampDataObject>().AsEnumerable().FirstOrDefault();
        if (item == null)
        {
            item = r.CreateObject<TimestampDataObject>();
        }

        item.LastSyncTime = DateTimeOffset.UtcNow;
        item.LastChangeDate = DateTimeOffset.UtcNow.AddMinutes(5);

        Debug.WriteLine($"({DateTime.UtcNow.ToString("hh:mm:ss.fff")}) WRITER: {JsonConvert.SerializeObject(item)}");
    });
});

读者:

Observable.Interval(TimeSpan.FromSeconds(10)).Subscribe(v =>
{
    var latestTimestampInfo = Realm.GetInstance().All<TimestampDataObject>();
    Debug.WriteLine($"({ DateTime.UtcNow.ToString("hh:mm:ss.fff")}) READER: {JsonConvert.SerializeObject(latestTimestampInfo)}");
});

不知道会发生什么。也许一些Realm的家伙可以澄清这一点。

更新

做了一些更多的测试,显然当读者和作者在同一个时一切正常Thread。在时间戳之后的日志中添加了托管线程 ID。因此,您可以在下面看到在线程 11 上运行的阅读器(与作者的相同)如何正常工作。但是在不同线程上运行的读取器会输出旧值:

//更新前(正确)

[0:] (10:56:53.679,11) 读者:[{"LastSyncTime":"2016-07-17T22:55:55.573+00:00","LastChangeDate":"2016-07-17T23:00: 55.576+00:00","IsManaged":true}]

//更新在线程11上完成

[0:] (10:56:55.552,11) WRITER: {"LastSyncTime":"2016-07-17T22:56:55.552+00:00","LastChangeDate":"2016-07-17T23:01:55.553 +00:00","IsManaged":true}

//线程 11 上的读取器输出正确的值

[0:] (10:57:03.702,11) 读者:[{"LastSyncTime":"2016-07-17T22:56:55.552+00:00","LastChangeDate":"2016-07-17T23:01: 55.553+00:00","IsManaged":true}]

//再次,阅读器在线程 11 上。正确输出。

[0:] (10:57:13.702,11) 读者:[{"LastSyncTime":"2016-07-17T22:56:55.552+00:00","LastChangeDate":"2016-07-17T23:01: 55.553+00:00","IsManaged":true}]

//线程 12 上的读取器输出不正确的结果

[0:] (10:57:23.703,12) 读者:[{"LastSyncTime":"2016-07-17T22:23:19.674+00:00","LastChangeDate":"2016-07-17T22:28: 19.676+00:00","IsManaged":true}]

//再次,阅读器在线程 11 上。正确输出。

[0:] (10:57:33.703,11) 读者:[{"LastSyncTime":"2016-07-17T22:56:55.552+00:00","LastChangeDate":"2016-07-17T23:01: 55.553+00:00","IsManaged":true}]

4

1 回答 1

1

没关系。看来我需要调用在没有事件循环的线程上创建和使用Realm.Refresh()的实例。Realm否则,它们与创建时的写入提交保持同步。

Realm.Refresh()导致领域前进到最新的写入提交并将其用于后续读取。

相关文件

当您最初在线程上打开 Realm 时,其状态将基于最近一次成功的写入提交,并且在刷新之前将保持在该版本上。领域会在每次运行循环迭代开始时自动刷新。如果线程没有运行循环(后台线程通常是这种情况),则必须手动调用 Realm.Refresh() 以将事务推进到最新状态。

阅读器部分现在看起来像这样:

Observable.Interval(TimeSpan.FromSeconds(10)).Subscribe(v =>
{
    var realm = Realm.GetInstance();
    realm.Refresh();
    var latestTimestampInfo = realm.All<TimestampDataObject>();
    Debug.WriteLine($"({ DateTime.UtcNow.ToString("hh:mm:ss.fff")},{Thread.CurrentThread.ManagedThreadId}) READER: {JsonConvert.SerializeObject(latestTimestampInfo)}");
});
于 2016-07-18T06:22:01.383 回答