并行读取和结果不一致的结果在境界中写道

时间:2016-07-17 22:23:39

标签: c# xamarin realm realm-net

也许我错过了一些东西但是我在Realm同时读取和写入时得到了一些奇怪的结果。

我第一次在一个更大的项目中遇到过这个问题,但现在只需要在测试项目中重现它。

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

我首先会显示输出,因为它最相关。 paranthesis中的时间是记录输出的时间。其余的是标识符(READER / WRITER),然后是RealmObject的JSON表示。

成功写入后,读者会读取旧值一段时间,然后读取新值,然后再次读取旧值。如果我重新启动应用程序,那么一切都很好,当然,有一段时间了。

  

//读者开始阅读。输出正确

     

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

     

// Writer进来并更新值。

     

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

     

//读者暂时读取不正确的(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":真}]   [0:](10:06:24.678)读者:   [{" LastSyncTime":" 2016-07-17T22:04:45.384 + 00:00"" LastChangeDate":" 2016-07-17T22 :09:45.384 + 00:00"" IsManaged":真}]   [0:](10:06:34.678)读者:   [{" LastSyncTime":" 2016-07-17T22:04:45.384 + 00:00"" LastChangeDate":" 2016-07-17T22 :09:45.384 + 00:00"" IsManaged":真}]

     

// Reader suddnely读取正确的值

     

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

     

//阅读器回退到之前的值(????)

     

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

代码:

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)读者:   [{&#34; LastSyncTime&#34;:&#34; 2016-07-17T22:55:55.573 + 00:00&#34;&#34; LastChangeDate&#34;:&#34; 2016-07-17T23 :00:55.576 + 00:00&#34;&#34; IsManaged&#34;:真}]

     

//更新在第11个主题上完成

     

[0:](10:56:55.552,11)作者:   {&#34; LastSyncTime&#34;:&#34; 2016-07-17T22:56:55.552 + 00:00&#34;&#34; LastChangeDate&#34;:&#34; 2016-07-17T23: 01:55.553 + 00:00&#34;&#34; IsManaged&#34;:真}

     

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

     

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

     

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

     

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

     

//线程12上的读者输出错误结果

     

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

     

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

     

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

1 个答案:

答案 0 :(得分:1)

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

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

相关documentation

  

当您最初在某个线程上打开一个Realm时,它的状态将基于   关闭最近成功的写入提交,它将保持打开状态   该版本直到刷新。领域会自动刷新   每次runloop迭代的开始。如果一个线程没有runloop   (然后,通常是后台线程中的情况)   必须手动调用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)}");
});