[英]Observable.Interval not updating UI with expected frequency
我正在嘗試模擬時鍾的行為。 為此,我創建了一個Observable.Interval
,它在指定的時間間隔后,以相等的時間量更新屬性的值。 該值與GUI數據綁定。
問題是:“時鍾”運行得比預期的慢得多,也就是說,時鍾值增加一秒需要花費一秒以上的時間。
所需的時間分辨率越精細(下面的MILLIS_INTERVAL
的值),問題MILLIS_INTERVAL
嚴重(我使用值MILLIS_INTERVAL
和1000的其他約數進行了測試,因為據記錄TimeSpan.FromMilliseconds
的最大分辨率為1ms )。
我希望可觀察到的回調能夠異步運行,並且盡管有一定的執行時間,但可以定期觸發,甚至可能並行觸發,但似乎頻率越大,滯后就越多。
視圖模型
using System; using System.ComponentModel; using System.Reactive.Linq; namespace IntervalClock { public class ViewModel : INotifyPropertyChanged { public double TimeSeconds { get { return _timeSeconds; } set { _timeSeconds = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TimeSeconds")); } } double _timeSeconds; const double MILLIS_INTERVAL = 10; public ViewModel() { Observable.Interval(TimeSpan.FromMilliseconds(MILLIS_INTERVAL)) .Subscribe(token => TimeSeconds += MILLIS_INTERVAL / 1000); } public event PropertyChangedEventHandler PropertyChanged; } }
主窗口:
<Window x:Class="IntervalClock.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntervalClock"
mc:Ignorable="d">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="{Binding TimeSeconds, StringFormat=N3}" FontSize="30"/>
</StackPanel>
</Window>
計時器似乎在同一線程上調用OnNext
,因此不會“異步”執行回調。
您可以創建自己的方法來調用線程池線程上的回調。 這是使用System.Timers.Timer
類的基本示例:
public static IObservable<long> Interval(TimeSpan interval)
{
return Observable.Create<long>(observer =>
{
long i = 0;
Timer _timer = new Timer(interval.TotalMilliseconds);
_timer.Elapsed += (s, e) => observer.OnNext(i++);
_timer.Start();
return Disposable.Create(() =>
{
_timer.Stop();
_timer.Dispose();
});
});
}
用法(只需調用您自己的Interval
方法而不是Observable.Interval
):
Interval(TimeSpan.FromMilliseconds(MILLIS_INTERVAL))
.Subscribe(token => TimeSeconds += MILLIS_INTERVAL / 1000);
這應該使“回調異步運行,並且盡管有一定的執行時間,但仍要以規則的時間間隔(可能是並行觸發)觸發”。
Observable.Interval
運算符對運行每個.OnNext
觸發之間的間隔進行.OnNext
。 因此,如果.OnNext
花費0.1s且間隔為1.0s,則有效期為1.1s。 但是,當然Windows不是實時操作系統,因此它具有漂移性。 您的實際時間可能會更大,尤其是在系統負載時。
這是我的處理方式:
var interval = TimeSpan.FromSeconds(1.0);
Observable
.Create<long>(o =>
{
var sw = Stopwatch.StartNew();
return
Observable
.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(interval.TotalSeconds / 10.0))
.Select(x => (long)sw.Elapsed.TotalSeconds)
.DistinctUntilChanged()
.Subscribe(o);
})
StopWatch
的使用為您提供了出色的經過時間精度。 計時器的觸發頻率比interval
觸發的頻率大約高10倍,因此在觸發時會出現+/- 10%的錯誤,但結果是相同的-從此可觀察值返回的是非常准確的“秒”值,只是不返回精確地每秒
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.