Home / Forums / Replacing Task.Delay in Game Loops with PeriodicTimer in Modern .NET

UnreliableCode Community

Developer Research, Reverse Engineering & Coding Community

Tutorial

Replacing Task.Delay in Game Loops with PeriodicTimer in Modern .NET

GameDevSam
Indie Game Developer
VIP
Rep: 90
Join Date: Jul 2020
Posts: 8
Thanks: 22
1y ago · Sep 24, 2024 3:50 PM
#1
In older C# tick loops, using
CODE
await Task.Delay(100)
inside a while-loop causes tick drift because the work execution time is added on top of the delay duration.

Using
CODE
PeriodicTimer
for tick loops with zero time drift:


CSHARP
public async Task RunGameLoopAsync(CancellationToken ct)
{
    // 60 Hz tick rate (16.66 ms)
    using PeriodicTimer timer = new PeriodicTimer(TimeSpan.FromMilliseconds(16.666));

    while (await timer.WaitForNextTickAsync(ct))
    {
        // Executes exactly on interval boundaries!
        UpdatePhysics();
        BroadcastGameState();
    }
}


Key Advantages:
- No Drift: Adjusts sleep intervals to account for work execution time.
- Zero Allocations:
CODE
WaitForNextTickAsync
returns a
CODE
ValueTask<bool>
with zero heap allocations per tick.
- Thread-Safe Cancellation: Gracefully exits as soon as
CODE
CancellationToken
cancels.
GameDevSam · Indie Game Developer
Solo indie dev building games with Unity, Monogame, and cust...
The following users thanked GameDevSam for this post:
AsyncMaster
Concurrency Geek
MEMBER
Rep: 72
Join Date: Jul 2020
Posts: 13
Thanks: 83
1y ago · Sep 24, 2024 8:35 PM
#2
CODE
PeriodicTimer
was such a welcome addition in .NET 6. Standard
CODE
System.Timers.Timer
fired callbacks on random threadpool threads requiring locks, whereas
CODE
PeriodicTimer
flows cleanly within a single async loop.
AsyncMaster · Concurrency Geek
Task Parallel Library (TPL), async/await internals, and lock...
DevDan
.NET Core & Cloud
MEMBER
Rep: 324
Join Date: Feb 2021
Posts: 16
Thanks: 65
1y ago · Sep 25, 2024 2:35 AM
#3
We use
CODE
PeriodicTimer
for our 20Hz server tick in a multiplayer card game. Steady CPU usage and zero GC pressure!
DevDan · .NET Core & Cloud
Writing clean C# code and microservices since .NET Core 2.1....