C
C#2y ago
SWEETPONY

❔ ✅ Why should I use Func<Task> in this situation?

I have following class:
public static class MemoryLeaksTest
{
private static readonly ILiteCollectionAsync<MqttDelivery> _liteCollection;

public static void Run()
{
new TimerService(TimeSpan.FromSeconds(1))
.Start(Write);

new TimerService(TimeSpan.FromSeconds(5))
.Start(Read);
}

private static async Task Read() =>
await _liteCollection
.Query()
.Limit(40)
.ToList();

private static async Task Write() =>
await _liteCollection
.Upsert(new MqttDelivery());
}
public static class MemoryLeaksTest
{
private static readonly ILiteCollectionAsync<MqttDelivery> _liteCollection;

public static void Run()
{
new TimerService(TimeSpan.FromSeconds(1))
.Start(Write);

new TimerService(TimeSpan.FromSeconds(5))
.Start(Read);
}

private static async Task Read() =>
await _liteCollection
.Query()
.Limit(40)
.ToList();

private static async Task Write() =>
await _liteCollection
.Upsert(new MqttDelivery());
}
public class TimerService
{
private Task _timerTask;
private readonly PeriodicTimer _timer;
private readonly CancellationTokenSource _cts = new();


public TimerService(TimeSpan interval)
{
_timer = new PeriodicTimer(interval);
}

public void Start(Func<Task> f)
{
_timerTask = Interval(f);
}

public async Task Stop()
{
_cts.Cancel();

if (_timerTask != null)
await _timerTask;

_cts.Dispose();
}

private async Task Interval(Func<Task> f)
{
try
{
while (await _timer.WaitForNextTickAsync(_cts.Token))
await f();
}
catch (OperationCanceledException) { }
}
}
public class TimerService
{
private Task _timerTask;
private readonly PeriodicTimer _timer;
private readonly CancellationTokenSource _cts = new();


public TimerService(TimeSpan interval)
{
_timer = new PeriodicTimer(interval);
}

public void Start(Func<Task> f)
{
_timerTask = Interval(f);
}

public async Task Stop()
{
_cts.Cancel();

if (_timerTask != null)
await _timerTask;

_cts.Dispose();
}

private async Task Interval(Func<Task> f)
{
try
{
while (await _timer.WaitForNextTickAsync(_cts.Token))
await f();
}
catch (OperationCanceledException) { }
}
}
logic is simple I just don't understand following: if I change Func<Task> to simple Task everythink wouldn't work
8 Replies
cap5lut
cap5lut2y ago
because of the loop in Interval(), with the factory u basically invoke the reading/writing (up to) multiple times. if u just pass a task, it would do the reading/writing at max once
SWEETPONY
SWEETPONYOP2y ago
I don't understand I pass a task to Interval method that should invoke task in this condition: while (await _timer.WaitForNextTickAsync(_cts.Token)) so.. it should wait wait for tick and invoke method
cap5lut
cap5lut2y ago
yeah, because await f();, which produces a new Task instance each time. if u just pass the task directly, it would look similar to await theTask;, which means after the first iteration of the loop the task will stay completed maybe this shows the difference in behavior better
public async Task Example1()
{
var task = Task.Delay(1000);
while (true)
{
await task;
Console.WriteLine("this will spam a lot");
}
}
public async Task Example2()
{
while (true)
{
var task = Task.Delay(1000);
await task;
Console.WriteLine("this will spam a lot");
}
}
public async Task Example1()
{
var task = Task.Delay(1000);
while (true)
{
await task;
Console.WriteLine("this will spam a lot");
}
}
public async Task Example2()
{
while (true)
{
var task = Task.Delay(1000);
await task;
Console.WriteLine("this will spam a lot");
}
}
Example1 would wait exactly once for 1 sec, Example2 always
SWEETPONY
SWEETPONYOP2y ago
I need time to understand this .. thanks for helping!
cap5lut
cap5lut2y ago
in Example1 exactly 1 task was created, so once await task; returns, task is completed, a subsequent await task; would instantly return, because of that in Example2, it always creates a new task, before awaiting it Task.Delay(1000) is basically the factory method for the task, just like f in ur code
SWEETPONY
SWEETPONYOP2y ago
ahhh I understand we create new task in while every time in second case thanks
cap5lut
cap5lut2y ago
yep (and with the Func<Task>)
Accord
Accord2y ago
Looks like nothing has happened here. I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server