diff --git a/RemoteExec.Client/LoadBalancingStrategies/LeastBacklogStrategy.cs b/RemoteExec.Client/LoadBalancingStrategies/LeastBacklogStrategy.cs index f39f8b7..fd61274 100644 --- a/RemoteExec.Client/LoadBalancingStrategies/LeastBacklogStrategy.cs +++ b/RemoteExec.Client/LoadBalancingStrategies/LeastBacklogStrategy.cs @@ -1,7 +1,11 @@ namespace RemoteExec.Client.LoadBalancingStrategies; +/// +/// A load balancing strategy that selects servers based on local backlog. +/// public class LeastBacklogStrategy : ILoadBalancingStrategy { + /// public ServerConnection? SelectServer(IEnumerable availableServers) { return availableServers.MinBy(s => s.TaskChannel.Reader.Count); diff --git a/RemoteExec.Client/RemoteExec.Client.csproj b/RemoteExec.Client/RemoteExec.Client.csproj index c43c42c..fa5dd3f 100644 --- a/RemoteExec.Client/RemoteExec.Client.csproj +++ b/RemoteExec.Client/RemoteExec.Client.csproj @@ -16,4 +16,10 @@ + + + + diff --git a/RemoteExec.Generators/RemoteExec.Generators.csproj b/RemoteExec.Generators/RemoteExec.Generators.csproj new file mode 100644 index 0000000..fdf27f7 --- /dev/null +++ b/RemoteExec.Generators/RemoteExec.Generators.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.0 + latest + true + + + + + + diff --git a/RemoteExec.Generators/RemoteExecutorOverloadGenerator.cs b/RemoteExec.Generators/RemoteExecutorOverloadGenerator.cs new file mode 100644 index 0000000..fa55728 --- /dev/null +++ b/RemoteExec.Generators/RemoteExecutorOverloadGenerator.cs @@ -0,0 +1,76 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; + +using System.Linq; +using System.Text; + +namespace RemoteExec.Generators; + +[Generator] +public class RemoteExecutorOverloadGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + context.RegisterPostInitializationOutput(ctx => + { + string source = GenerateOverloads(16); + ctx.AddSource("RemoteExecutor.Overloads.g.cs", SourceText.From(source, Encoding.UTF8)); + }); + } + + private static string GenerateOverloads(int maxArgs) + { + StringBuilder sb = new StringBuilder(); + _ = sb.AppendLine("// "); + _ = sb.AppendLine("using System;"); + _ = sb.AppendLine("using System.Threading;"); + _ = sb.AppendLine("using System.Threading.Tasks;"); + _ = sb.AppendLine(); + _ = sb.AppendLine("namespace RemoteExec.Client;"); + _ = sb.AppendLine(); + _ = sb.AppendLine("public partial class RemoteExecutor"); + _ = sb.AppendLine("{"); + + for (int i = 0; i <= maxArgs; i++) + { + // T1, T2, T3... + string typeParams = i == 0 ? "" : string.Join(", ", Enumerable.Range(1, i).Select(n => $"T{n}")); + // T1 arg1, T2 arg2... + string methodParams = i == 0 ? "" : string.Join(", ", Enumerable.Range(1, i).Select(n => $"T{n} arg{n}")); + // arg1, arg2... + string callArgs = i == 0 ? "" : string.Join(", ", Enumerable.Range(1, i).Select(n => $"arg{n}!")); + + // Async overloads (Task) + string genericBracket = i == 0 ? "" : $"<{typeParams}, TResult>"; + string funcType = i == 0 ? "Func>" : $"Func<{typeParams}, Task>"; + + _ = sb.AppendLine($$""" + /// Generates a remote execution call for {{i}} async arguments. + public async Task ExecuteAsync{{genericBracket}}( + {{funcType}} @delegate, + {{methodParams}}{{(i > 0 ? ", " : "")}}CancellationToken ct = default) + { + return await ExecuteAsync<{{funcType}}, TResult>(@delegate, ct{{(i > 0 ? ", " : "")}}{{callArgs}}); + } + + """); + + // Sync overloads (Func) + string syncFuncType = i == 0 ? "Func" : $"Func<{typeParams}, TResult>"; + + _ = sb.AppendLine($$""" + /// Generates a remote execution call for {{i}} synchronous arguments. + public async Task ExecuteAsync{{genericBracket}}( + {{syncFuncType}} @delegate, + {{methodParams}}{{(i > 0 ? ", " : "")}}CancellationToken ct = default) + { + return await ExecuteAsync<{{syncFuncType}}, TResult>(@delegate, ct{{(i > 0 ? ", " : "")}}{{callArgs}}); + } + + """); + } + + _ = sb.AppendLine("}"); + return sb.ToString(); + } +} \ No newline at end of file diff --git a/RemoteExec.slnx b/RemoteExec.slnx index e89b600..a2ab5cc 100644 --- a/RemoteExec.slnx +++ b/RemoteExec.slnx @@ -1,6 +1,7 @@ + diff --git a/RemoteExec/Program.cs b/RemoteExec/Program.cs index 352e191..4c99952 100644 --- a/RemoteExec/Program.cs +++ b/RemoteExec/Program.cs @@ -22,8 +22,11 @@ await singleHostExecutor.StartAsync(); await Parallel.ForAsync(0, 1000, async (i, cancellationToken) => { - int r = await singleHostExecutor.ExecuteAsync>, int>(Multiply, i, i + 1); + int r = await singleHostExecutor.ExecuteAsync(Multiply, i, i + 1, cancellationToken); Console.WriteLine($"Multiply {i} * {i + 1} = {r}"); + + int s = await singleHostExecutor.ExecuteAsync(Add, i, i + 1, cancellationToken); + Console.WriteLine($"Add {i} + {i + 1} = {s}"); }); await singleHostExecutor.StopAsync(); @@ -32,4 +35,9 @@ static async Task Multiply(int x, int y) { await Task.Delay(Random.Shared.Next(100, 500)); return x.Multiply(y); +} + +static int Add(int x, int y) +{ + return x + y; } \ No newline at end of file