也许我遗漏了一些东西,但是在从同一个对象的 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}]