protected override void AfterRunningAllTasks() { const long MaxDelayMilliseconds = int.MaxValue - 1; #if DEBUG base.AfterRunningAllTasks(); #endif if (IsShuttingDown) { // Immediate shutdown WakeUp(true); return; } long nextTimeout = DefaultBreakoutTime; if (HasTasks) { _ = _timerHandle.Start(nextTimeout, 0); } else { if (ScheduledTaskQueue.TryPeek(out IScheduledRunnable nextScheduledTask)) { long delayNanos = nextScheduledTask.DelayNanos; if ((ulong)delayNanos > 0UL) // delayNanos >= 0 { var timeout = PreciseTime.ToMilliseconds(delayNanos); nextTimeout = Math.Min(timeout, MaxDelayMilliseconds); } _ = _timerHandle.Start(nextTimeout, 0); } } }
public void ScheduleLaggyTaskAtFixedRate() { var timestamps = new BlockingCollection <long>(); int expectedTimeStamps = 5; var allTimeStampsLatch = new CountdownEvent(expectedTimeStamps); var f = this.eventLoop.ScheduleAtFixedRate(() => { var empty = timestamps.Count == 0; timestamps.Add(Stopwatch.GetTimestamp()); if (empty) { try { Thread.Sleep(401); } catch { } } allTimeStampsLatch.Signal(); }, TimeSpan.FromMilliseconds(100), TimeSpan.FromMilliseconds(100)); Assert.True(allTimeStampsLatch.Wait(TimeSpan.FromMinutes(1))); Assert.True(f.Cancel()); Thread.Sleep(300); Assert.Equal(expectedTimeStamps, timestamps.Count); // Check if the task was run with lag. int i = 0; long?previousTimestamp = null; foreach (long t in timestamps) { if (previousTimestamp == null) { previousTimestamp = t; continue; } long diff = t - previousTimestamp.Value; if (i == 0) { Assert.True(diff >= PreciseTime.ToDelayNanos(TimeSpan.FromMilliseconds(400))); } else { //Assert.True(diff <= PreciseTime.ToDelayNanos(TimeSpan.FromMilliseconds(10 + 2))); var diffMs = PreciseTime.ToMilliseconds(diff); Assert.True(diffMs <= 10 + 40); // libuv 多加 40,确保测试通过 } previousTimestamp = t; i++; } }
protected sealed override IRunnable PollTask() { const long MaxDelayMilliseconds = int.MaxValue - 1; Debug.Assert(InEventLoop); var taskQueue = _taskQueue; var task = PollTaskFrom(taskQueue); if (task is object) { return(task); } #if DEBUG if (_tailTasks.IsEmpty) { _emptyEvent.Reset(); } #else _emptyEvent.Reset(); #endif task = PollTaskFrom(taskQueue); if (task is object || IsShuttingDown) // revisit queue as producer might have put a task in meanwhile { return(task); } // revisit queue as producer might have put a task in meanwhile if (TryPeekScheduledTask(out IScheduledRunnable nextScheduledTask)) { var delayNanos = nextScheduledTask.DelayNanos; if ((ulong)delayNanos > 0UL) // delayNanos 为非负值 { var timeout = PreciseTime.ToMilliseconds(delayNanos); _emptyEvent.Wait((int)Math.Min(timeout, MaxDelayMilliseconds)); } } else { if (!IsShuttingDown) { _emptyEvent.Wait(); } task = PollTaskFrom(taskQueue); } return(task); }
private bool TryTakeTask(long delayNanos, out IRunnable task) { const long MaxDelayMilliseconds = int.MaxValue - 1; if ((ulong)delayNanos > 0UL) // delayNanos 为非负值 { var timeout = PreciseTime.ToMilliseconds(delayNanos); if (_blockingTaskQueue.TryTake(out task, (int)Math.Min(timeout, MaxDelayMilliseconds))) { return(true); } } // We need to fetch the scheduled tasks now as otherwise there may be a chance that // scheduled tasks are never executed if there is always one task in the taskQueue. // This is for example true for the read task of OIO Transport // See https://github.com/netty/netty/issues/1614 _ = FetchFromScheduledTaskQueue(); return(_blockingTaskQueue.TryTake(out task, 0)); }