1

多分私は何かを見逃しているかもしれませんが、同じオブジェクトであるレルムから並行して読み書きしているときに、奇妙な結果が得られます。

これは、より大きなプロジェクトで最初に発生しましたが、テスト プロジェクトで再現することができました。

シナリオ: 2 つのフィールドRealmObjectを持つ 1 つのオブジェクト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) ライター: {"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}]

//リーダーは突然正しい値を読み取ります

[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}]

//リーダーは以前の値に戻ります (????)

[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)}");
});

何が起こるかわからない。おそらく、レルムの何人かがこれを明確にすることができます.

アップデート

さらにいくつかのテストを行ったところ、リーダーとライターが同じ場合、すべて正常に動作するよう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) ライター: {"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 に答える