From a35959b30026c089ee1538dfaeca0a67e9cac6de Mon Sep 17 00:00:00 2001 From: maks march <1maks_2055@mail.ru> Date: Mon, 23 Feb 2026 22:47:02 +0500 Subject: [PATCH 1/4] parallel task --- .../Clients/ParallelClusterClient.cs | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/homework 2/ClusterClient/Clients/ParallelClusterClient.cs b/homework 2/ClusterClient/Clients/ParallelClusterClient.cs index 5531800..2e659a7 100644 --- a/homework 2/ClusterClient/Clients/ParallelClusterClient.cs +++ b/homework 2/ClusterClient/Clients/ParallelClusterClient.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using log4net; @@ -11,11 +12,44 @@ public class ParallelClusterClient : ClusterClientBase { public ParallelClusterClient(string[] replicaAddresses) : base(replicaAddresses) { + ReplicaAddresses = replicaAddresses; } - public override Task ProcessRequestAsync(string query, TimeSpan timeout) + public override async Task ProcessRequestAsync(string query, TimeSpan timeout) { - throw new NotImplementedException(); + var tasks = ReplicaAddresses + .Select(address => CallRequest(address, query)) + .ToList(); + + var timeoutTask = Task.Delay(timeout).ContinueWith(_ => throw new TimeoutException()); + tasks.Add(timeoutTask); + + while (tasks.Count > 1) + { + var completedTask = await Task.WhenAny(tasks); + if (completedTask == timeoutTask) + await timeoutTask; + try + { + return await completedTask; + } + catch + { + tasks.Remove(completedTask); + if (tasks.Count == 1) throw new Exception(); + } + } + throw new TimeoutException(); + } + + private Task CallRequest(string address, string query) + { + var uri = new UriBuilder(address) + { + Query = $"query={query}" + }.Uri.AbsoluteUri; + + return ProcessRequestAsync(CreateRequest(uri)); } protected override ILog Log => LogManager.GetLogger(typeof(ParallelClusterClient)); From 1dfe019def9c41ee5bd5770db75c5fd484b3996a Mon Sep 17 00:00:00 2001 From: maks march <1maks_2055@mail.ru> Date: Tue, 24 Feb 2026 16:08:45 +0500 Subject: [PATCH 2/4] roundrobin task --- .../Clients/RoundRobinClusterClient.cs | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs b/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs index 0293628..1a48994 100644 --- a/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs +++ b/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs @@ -11,11 +11,40 @@ public class RoundRobinClusterClient : ClusterClientBase { public RoundRobinClusterClient(string[] replicaAddresses) : base(replicaAddresses) { + ReplicaAddresses = replicaAddresses; } - public override Task ProcessRequestAsync(string query, TimeSpan timeout) + public override async Task ProcessRequestAsync(string query, TimeSpan timeout) { - throw new NotImplementedException(); + var replicaTimeout = timeout / ReplicaAddresses.Length; + + foreach (var address in ReplicaAddresses) + { + var task = CallRequest(address, query); + var timeoutTask = Task.Delay(replicaTimeout); + var completedTask = await Task.WhenAny(task, timeoutTask); + if (completedTask == timeoutTask) + continue; + try + { + return await task; + } + catch + { + + } + } + throw new TimeoutException(); + } + + private Task CallRequest(string address, string query) + { + var uri = new UriBuilder(address) + { + Query = $"query={query}" + }.Uri.AbsoluteUri; + + return ProcessRequestAsync(CreateRequest(uri)); } protected override ILog Log => LogManager.GetLogger(typeof(RoundRobinClusterClient)); From 0b08b94cba5d1785145f3277a8a063cc7032a092 Mon Sep 17 00:00:00 2001 From: maks march <1maks_2055@mail.ru> Date: Tue, 24 Feb 2026 17:26:26 +0500 Subject: [PATCH 3/4] smart task --- .../Clients/ClusterClientBase.cs | 10 +++++++ .../Clients/RoundRobinClusterClient.cs | 10 ------- .../Clients/SmartClusterClient.cs | 28 +++++++++++++++++-- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/homework 2/ClusterClient/Clients/ClusterClientBase.cs b/homework 2/ClusterClient/Clients/ClusterClientBase.cs index 23a2ffd..9bc479a 100644 --- a/homework 2/ClusterClient/Clients/ClusterClientBase.cs +++ b/homework 2/ClusterClient/Clients/ClusterClientBase.cs @@ -40,5 +40,15 @@ protected async Task ProcessRequestAsync(WebRequest request) return result; } } + + protected Task CallRequest(string address, string query) + { + var uri = new UriBuilder(address) + { + Query = $"query={query}" + }.Uri.AbsoluteUri; + + return ProcessRequestAsync(CreateRequest(uri)); + } } } \ No newline at end of file diff --git a/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs b/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs index 1a48994..7a55ce6 100644 --- a/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs +++ b/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs @@ -37,16 +37,6 @@ public override async Task ProcessRequestAsync(string query, TimeSpan ti throw new TimeoutException(); } - private Task CallRequest(string address, string query) - { - var uri = new UriBuilder(address) - { - Query = $"query={query}" - }.Uri.AbsoluteUri; - - return ProcessRequestAsync(CreateRequest(uri)); - } - protected override ILog Log => LogManager.GetLogger(typeof(RoundRobinClusterClient)); } } diff --git a/homework 2/ClusterClient/Clients/SmartClusterClient.cs b/homework 2/ClusterClient/Clients/SmartClusterClient.cs index eb06d8b..d08f33c 100644 --- a/homework 2/ClusterClient/Clients/SmartClusterClient.cs +++ b/homework 2/ClusterClient/Clients/SmartClusterClient.cs @@ -11,11 +11,35 @@ public class SmartClusterClient : ClusterClientBase { public SmartClusterClient(string[] replicaAddresses) : base(replicaAddresses) { + ReplicaAddresses = replicaAddresses; } - public override Task ProcessRequestAsync(string query, TimeSpan timeout) + public override async Task ProcessRequestAsync(string query, TimeSpan timeout) { - throw new NotImplementedException(); + var replicaTimeout = timeout / ReplicaAddresses.Length; + var runningTasks = new List>(); + + foreach (var address in ReplicaAddresses) + { + var task = CallRequest(address, query); + var timeoutTask = Task.Delay(replicaTimeout).ContinueWith(_ => throw new TimeoutException()); + runningTasks.Add(task); + runningTasks.Add(timeoutTask); + var completedTask = await Task.WhenAny(runningTasks); + + runningTasks.Remove(timeoutTask); + if (completedTask == timeoutTask) + { + continue; + } + + if (completedTask.Status == TaskStatus.RanToCompletion) + { + return completedTask.Result; + } + runningTasks.Remove(completedTask); + } + throw new TimeoutException(); } protected override ILog Log => LogManager.GetLogger(typeof(SmartClusterClient)); From e4ca40eb7c534cfe5a5ee919b2c4dc6d625f6aa6 Mon Sep 17 00:00:00 2001 From: maks march <1maks_2055@mail.ru> Date: Tue, 24 Feb 2026 20:21:50 +0500 Subject: [PATCH 4/4] extra task --- .../Clients/RoundRobinClusterClient.cs | 30 +++++++++++--- .../Clients/SmartClusterClient.cs | 41 +++++++++++++++---- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs b/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs index 7a55ce6..e81a620 100644 --- a/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs +++ b/homework 2/ClusterClient/Clients/RoundRobinClusterClient.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,34 +11,52 @@ namespace ClusterClient.Clients { public class RoundRobinClusterClient : ClusterClientBase { + private ConcurrentDictionary _stats; + public RoundRobinClusterClient(string[] replicaAddresses) : base(replicaAddresses) { ReplicaAddresses = replicaAddresses; + _stats = new (); + foreach (var addr in replicaAddresses) + { + _stats.TryAdd(addr, TimeSpan.MaxValue); + } } public override async Task ProcessRequestAsync(string query, TimeSpan timeout) { - var replicaTimeout = timeout / ReplicaAddresses.Length; - - foreach (var address in ReplicaAddresses) + var orderedReplicas = ReplicaAddresses + .OrderBy(addr => _stats.GetValueOrDefault(addr, TimeSpan.MaxValue)) + .ToArray(); + + for (int i = 0; i < ReplicaAddresses.Length; i++) { + var replicaTimeout = timeout / (ReplicaAddresses.Length - i); + var address = orderedReplicas[i]; var task = CallRequest(address, query); var timeoutTask = Task.Delay(replicaTimeout); + var sw = Stopwatch.StartNew(); var completedTask = await Task.WhenAny(task, timeoutTask); + + sw.Stop(); + _stats[address] = sw.Elapsed; + timeout -= sw.Elapsed; if (completedTask == timeoutTask) + { continue; + } + try { return await task; } catch { - + _stats[address] = TimeSpan.MaxValue; } } throw new TimeoutException(); } - protected override ILog Log => LogManager.GetLogger(typeof(RoundRobinClusterClient)); } } diff --git a/homework 2/ClusterClient/Clients/SmartClusterClient.cs b/homework 2/ClusterClient/Clients/SmartClusterClient.cs index d08f33c..c0f1341 100644 --- a/homework 2/ClusterClient/Clients/SmartClusterClient.cs +++ b/homework 2/ClusterClient/Clients/SmartClusterClient.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,33 +11,54 @@ namespace ClusterClient.Clients { public class SmartClusterClient : ClusterClientBase { + private ConcurrentDictionary _stats; + public SmartClusterClient(string[] replicaAddresses) : base(replicaAddresses) { ReplicaAddresses = replicaAddresses; + _stats = new (); + foreach (var addr in replicaAddresses) + { + _stats.TryAdd(addr, TimeSpan.MaxValue); + } } public override async Task ProcessRequestAsync(string query, TimeSpan timeout) { - var replicaTimeout = timeout / ReplicaAddresses.Length; - var runningTasks = new List>(); + var runningTasks = new Dictionary, string>(); - foreach (var address in ReplicaAddresses) + var orderedReplicas = ReplicaAddresses + .OrderBy(addr => _stats.GetValueOrDefault(addr, TimeSpan.MaxValue)) + .ToArray(); + + for (int i = 0; i < ReplicaAddresses.Length; i++) { + var replicaTimeout = timeout / (ReplicaAddresses.Length - i); + var address = orderedReplicas[i]; var task = CallRequest(address, query); var timeoutTask = Task.Delay(replicaTimeout).ContinueWith(_ => throw new TimeoutException()); - runningTasks.Add(task); - runningTasks.Add(timeoutTask); - var completedTask = await Task.WhenAny(runningTasks); - + runningTasks.Add(task, address); + runningTasks.Add(timeoutTask, "timeout"); + var sw = Stopwatch.StartNew(); + var completedTask = await Task.WhenAny(runningTasks.Keys); + sw.Stop(); + runningTasks.Remove(timeoutTask); + + timeout -= sw.Elapsed; if (completedTask == timeoutTask) { continue; } - if (completedTask.Status == TaskStatus.RanToCompletion) + try + { + _stats[runningTasks[completedTask]] = sw.Elapsed; + return await completedTask; + } + catch { - return completedTask.Result; + _stats[runningTasks[completedTask]] = TimeSpan.MaxValue; } runningTasks.Remove(completedTask); }