C
C#5mo ago
Самке

Updating progress on the screen problem

I am learning about asynchronous programming and i run into a problem with updating progress from async task. For some reason the task is doing its job correctly but the progress.ProgressChanged event doesn't update the progress on the screen correctly.
c#
public static async Task<long> CalculateSumAsync(int n, CancellationToken token, IProgress<(int, long)>? progress = null)
{
if (n <= 0)
{
throw new ArgumentOutOfRangeException(nameof(n));
}

long result = 0;

var res = await Task.Run(() =>
{
for (var i = 1; i <= n; i++)
{
result += i;

token.ThrowIfCancellationRequested();

progress?.Report((i, result));
}

return result;
});

return res;
}
c#
public static async Task<long> CalculateSumAsync(int n, CancellationToken token, IProgress<(int, long)>? progress = null)
{
if (n <= 0)
{
throw new ArgumentOutOfRangeException(nameof(n));
}

long result = 0;

var res = await Task.Run(() =>
{
for (var i = 1; i <= n; i++)
{
result += i;

token.ThrowIfCancellationRequested();

progress?.Report((i, result));
}

return result;
});

return res;
}
c#
progress.ProgressChanged += (sender, tuple) =>
{
latestProgress = tuple;
Console.WriteLine($"index: {latestProgress.progressValue} progress: {latestProgress.progressLong}");
};
c#
progress.ProgressChanged += (sender, tuple) =>
{
latestProgress = tuple;
Console.WriteLine($"index: {latestProgress.progressValue} progress: {latestProgress.progressLong}");
};
Result: Press C to exit Enter the number: 15 index: 1 progress: 1 index: 3 progress: 6 index: 3 progress: 6 index: 3 progress: 6 index: 3 progress: 6 index: 8 progress: 36 index: 9 progress: 45 index: 8 progress: 45 index: 10 progress: 55 index: 11 progress: 66 index: 15 progress: 120 index: 14 progress: 105 index: 6 progress: 21 Final result: 120 index: 13 progress: 91 index: 12 progress: 78
9 Replies
Самке
СамкеOP5mo ago
And if i add the Task.Delay(1).Wait(); in my Calc task then i will get the correct output Result after modification: Press C to exit Enter the number: 15 index: 1 progress: 1 index: 2 progress: 3 index: 3 progress: 6 index: 4 progress: 10 index: 5 progress: 15 index: 6 progress: 21 index: 7 progress: 28 index: 8 progress: 36 index: 9 progress: 45 index: 10 progress: 55 index: 11 progress: 66 index: 12 progress: 78 index: 13 progress: 91 index: 14 progress: 105 index: 15 progress: 120 Final result: 120 Can this be solved without adding that line?
Anton
Anton5mo ago
yes, just print the local tuple that's happening because you're copying it to a variable
Самке
СамкеOP5mo ago
c#
progress.ProgressChanged += (sender, tuple) =>
{
Console.WriteLine($"index: {tuple.index} progress: {tuple.currNumber}");
};
c#
progress.ProgressChanged += (sender, tuple) =>
{
Console.WriteLine($"index: {tuple.index} progress: {tuple.currNumber}");
};
Result: Press C to exit Enter the number: 15 index: 2 progress: 3 index: 1 progress: 1 index: 5 progress: 15 index: 3 progress: 6 index: 4 progress: 10 index: 10 progress: 55 index: 6 progress: 21 index: 8 progress: 36 index: 7 progress: 28 index: 15 progress: 120 index: 13 progress: 91 index: 12 progress: 78 index: 9 progress: 45 index: 11 progress: 66 index: 14 progress: 105 Final result: 120
Anton
Anton5mo ago
yeah i think that's just normal it's the right data, in the wrong order if you want synchronization, you may want an event queue sort of thing or making the callback async and awaiting it to be clear, the order is wrong because of WriteLine
Самке
СамкеOP5mo ago
why because WriteLine?
Anton
Anton5mo ago
I think no actually it doesn't make sense for it to do that, since the loops are synchronous
Самке
СамкеOP5mo ago
To be honest this is just an exercise so it is not something important to me 😁 but still it was odd to see result in a wrong order. I think i will stick with Task.Delay for now and i will do a little bit of research on event queue and callback async
canton7
canton75mo ago
Is this a console application? When you do new Progress<T>(), it captures the current SynchronizationContext. When you do progress.Report, it posts a message to that SynchronizationContext. This means that if you do new Progress<T> on the UI thread, it will capture a SynchronizationContext which will post messages back to the UI thread, which is normally what you want, as you can use the ProgressChanged event to interact with UI elements. However, if you do new Progress<T>() on a thread which doesn't have a SynchronizationContext (such as the main thread of a console application), then it will capture a SynchronizationContext which just posts messages to the thread pool. This means that when you do progress.Report, it will post the progress update to the thread pool, and any old threadpool thread will pick it up and execute it. There's no ordering guarantee in things posted to the threadpool, so you might well see progress updates arriving out of order. That also explains why progress updates continue to happen after the final result is available: the final result Task might complete before the threadpool threads have had a chance to process all of the progress updates which were queued
Anton
Anton5mo ago
Ah I thought it was just a synchronous callback function I was wondering how a blocking function could desync
Want results from more Discord servers?
Add your server