I'm unsure about two possibilities to react to an event in my code. Mostly I'm concerned about which one needs less resources.
I have a method with an observer registered to an eventproducer
. If the eventproducer
returns something, the method exits and the caller of the method starts the method again (you can think of it as a kind of a long polling).
The eventproducer
sometimes fires lots of events per seconds and sometimes rests for minutes.
The first approach was to await a delay of 500ms and then check if there is something to return or otherwise (until a timeout of 5 minutes) again delay for 500ms.
eventProducer.RegisterListener((events)=>{evList.Add(events)});
while(evList.Count=0 && !TimeOut){
await Task.Delay(500);}
eventProducer.UnRegister(...);
// return evList, method gets recalled immediately
The second approach was to use a CancellationToken
. If the eventproducer
produces something, the CancellationTokenSource
cancels the source. And in the method I wait for Task.Delay(5min, cancellationToken)
.
eventProducer.RegisterListener((events)=>{evList.Add(events);
cancelSource.Cancel();}
try
{
await Task.Delay(5min, cancellationToken)
}
catch(TaskCanceledException){//nothing to do};
eventProducer.UnRegister(...);
// return evList, method gets recalled immediately
The advantages of the second approach are that the method immediately returns if the producer produces something and that we don't have to await and awake in a loop.
But with the second approach every time the producer produces something, a TaskCanceledException
is thrown. I'm concerned that this could affect system load more than the awake and await every 500ms especially i times when the eventproducer
produces lots of events.
Am I overestimating the cost of throwing and catching an exception? And is there a way to cancel Task.Delay
with a CancellationToken
but without throwing a TaskCanceledException
? I.E. something like task.setComplete
?
If you want an immediate notification similar to what a cancellation gives you but without an exception you can simply use
TaskCompletionSource
.TaskCompletionSource
is how you create a promise task. You get an uncompleted task from theTask
property and you complete it (or cancel) withSetResult
. You can use it to actually pass on the result itself:This solution doesn't have any exceptions and doesn't use unnecessary polling
To answer your specific questions:
Probably. You need to test and prove it's really an issue.
Yes. Add an empty continuation: