OSDN Git Service

RefreshTimelineを呼び出す最小間隔をTimerで制御する
authorKimura Youichi <kim.upsilon@bucyou.net>
Wed, 15 Aug 2018 13:54:46 +0000 (22:54 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Thu, 16 Aug 2018 18:26:47 +0000 (03:26 +0900)
OpenTween/Tween.cs

index a68cdc5..3c0a684 100644 (file)
@@ -1380,7 +1380,64 @@ namespace OpenTween
             await Task.WhenAll(refreshTasks);
         }
 
+        private TimeSpan refreshInterval = TimeSpan.Zero;
+        private DateTimeUtc lastRefreshRequested = DateTimeUtc.MinValue;
+        private DateTimeUtc lastRefreshed = DateTimeUtc.MinValue;
+        private System.Threading.Timer refreshThrottlingTimer = null;
+        private int refreshTimerEnabled = 0;
+
         private void RefreshTimeline()
+            => this.RefreshTimelineThrottling();
+
+        private void RefreshTimelineThrottling()
+        {
+            const int TIMER_DISABLED = 0;
+            const int TIMER_ENABLED = 1;
+
+            async void timerCallback()
+            {
+                var timerExpired = this.lastRefreshRequested < this.lastRefreshed;
+                if (timerExpired)
+                {
+                    // 前回実行時より後に lastRefreshRequested が更新されていなければタイマーを止める
+                    Interlocked.CompareExchange(ref this.refreshTimerEnabled, TIMER_DISABLED, TIMER_ENABLED);
+                }
+                else
+                {
+                    this.lastRefreshed = DateTimeUtc.Now;
+
+                    await this.InvokeAsync(() => this.RefreshTimelineInternal())
+                        .ConfigureAwait(false);
+
+                    // dueTime は timerCallback が呼ばれる度に再設定する (period は使用しない)
+                    // これにより RefreshTimeline の実行に refreshInterval 以上の時間が掛かっても重複して実行されることはなくなる
+                    lock (this.refreshThrottlingTimer)
+                        this.refreshThrottlingTimer.Change(dueTime: (int)this.refreshInterval.TotalMilliseconds, period: Timeout.Infinite);
+                }
+            }
+
+            if (this.refreshThrottlingTimer == null)
+            {
+                var newTimer = new System.Threading.Timer(_ => timerCallback());
+
+                // Timer インスタンスの生成が同時に複数行われた場合は先に代入された方を優先する
+                if (Interlocked.CompareExchange(ref this.refreshThrottlingTimer, newTimer, null) != null)
+                    newTimer.Dispose();
+            }
+
+            this.lastRefreshRequested = DateTimeUtc.Now;
+
+            if (this.refreshTimerEnabled == TIMER_DISABLED)
+            {
+                lock (this.refreshThrottlingTimer)
+                {
+                    if (Interlocked.CompareExchange(ref this.refreshTimerEnabled, TIMER_ENABLED, TIMER_DISABLED) == TIMER_DISABLED)
+                        this.refreshThrottlingTimer.Change(dueTime: 0, period: Timeout.Infinite);
+                }
+            }
+        }
+
+        private void RefreshTimelineInternal()
         {
             var curTabModel = this._statuses.Tabs[this._curTab.Text];
 
@@ -11371,9 +11428,7 @@ namespace OpenTween
             }
         }
 
-        private int userStreamsRefreshing = 0;
-
-        private async void tw_NewPostFromStream(object sender, EventArgs e)
+        private void tw_NewPostFromStream(object sender, EventArgs e)
         {
             if (SettingManager.Common.ReadOldPosts)
             {
@@ -11384,19 +11439,7 @@ namespace OpenTween
 
             if (SettingManager.Common.UserstreamPeriod > 0) return;
 
-            // userStreamsRefreshing が 0 (インクリメント後は1) であれば RefreshTimeline を実行
-            if (Interlocked.Increment(ref this.userStreamsRefreshing) == 1)
-            {
-                try
-                {
-                    await this.InvokeAsync(() => this.RefreshTimeline())
-                        .ConfigureAwait(false);
-                }
-                finally
-                {
-                    Interlocked.Exchange(ref this.userStreamsRefreshing, 0);
-                }
-            }
+            this.RefreshTimeline();
         }
 
         private async void tw_UserStreamStarted(object sender, EventArgs e)