// Exercise 1: sequential vs concurrent awaiting (easy) // // FetchPriceAsync simulates an I/O call that takes ~200ms. // // Implement: // - SumSequentialAsync(ids): awaits each FetchPriceAsync one after another // and returns the sum. (Expected total time: ~200ms * ids.Length.) // - SumConcurrentAsync(ids): STARTS every FetchPriceAsync first, then // awaits them all with Task.WhenAll and returns the sum. // (Expected total time: ~200ms regardless of ids.Length.) // // The self-check measures elapsed time with a Stopwatch, so a "concurrent" // version that secretly awaits in a loop will FAIL. // // Run with: dotnet run (inside a console project). using System; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; class Program { static async Task FetchPriceAsync(int id) { await Task.Delay(200); // stands in for a network call return id * 10; } #pragma warning disable IDE0060, CS1998 static async Task SumSequentialAsync(int[] ids) { // TODO: foreach id, total += await FetchPriceAsync(id) return 0; } static async Task SumConcurrentAsync(int[] ids) { // TODO: var tasks = ids.Select(FetchPriceAsync).ToArray(); // int[] prices = await Task.WhenAll(tasks); return 0; } #pragma warning restore IDE0060, CS1998 static async Task Main() { int pass = 0, total = 0; int[] ids = { 1, 2, 3, 4, 5 }; var sw = Stopwatch.StartNew(); int seq = await SumSequentialAsync(ids); long seqMs = sw.ElapsedMilliseconds; sw.Restart(); int con = await SumConcurrentAsync(ids); long conMs = sw.ElapsedMilliseconds; total++; if (seq == 150 && seqMs >= 900) { Console.WriteLine($"PASS: sequential sum ({seqMs}ms)"); pass++; } else Console.WriteLine($"FAIL: sequential sum={seq} in {seqMs}ms (expected 150, >=900ms)"); total++; if (con == 150 && conMs < 600) { Console.WriteLine($"PASS: concurrent sum ({conMs}ms)"); pass++; } else Console.WriteLine($"FAIL: concurrent sum={con} in {conMs}ms (expected 150, <600ms)"); Console.WriteLine($"--- {pass}/{total} checks passed ---"); } }