C# C服务内的动态客户端节流

C# C服务内的动态客户端节流,c#,async-await,httprequest,throttling,C#,Async Await,Httprequest,Throttling,我有一个客户机应用程序,它将运行大量的作业,大约10k,foreach将向web api发出http请求。每个作业都是半长时间运行,响应时间不可预测,为7-90秒 我正在努力减少所有工作的总时间。我注意到,如果我一次发出太多请求,响应时间会急剧增加,因为服务器基本上被关闭了。这使得所有工作岗位的总数一路上升。我一直在使用SemaphoreSlim静态设置并行顺序,但需要找到一种基于当前响应时间动态调整的方法,以获得最低的总体响应时间。这是我一直在使用的代码 List<Task<Dat

我有一个客户机应用程序,它将运行大量的作业,大约10k,foreach将向web api发出http请求。每个作业都是半长时间运行,响应时间不可预测,为7-90秒

我正在努力减少所有工作的总时间。我注意到,如果我一次发出太多请求,响应时间会急剧增加,因为服务器基本上被关闭了。这使得所有工作岗位的总数一路上升。我一直在使用SemaphoreSlim静态设置并行顺序,但需要找到一种基于当前响应时间动态调整的方法,以获得最低的总体响应时间。这是我一直在使用的代码

List<Task<DataTable>> tasks = new List<Task<DataTable>>();
SemaphoreSlim throttler = new SemaphoreSlim(40, 300);
foreach (DataRow entry in newEntries.Rows)
{
    await throttler.WaitAsync();

    tasks.Add(Task<DataTable>.Run(async () =>
    {
        try
        {
            return RunRequest(entry); //Http requests and other logic is done here
        }
        finally
        {
            throttler.Release();
        }
    }
    ));
}
await Task.WhenAll(tasks.ToArray());
我知道那个节流阀。释放;一次可以传递不同的数字以增加未完成请求的总数,调用Wait而不释放将从计数中减去

我认为需要保持某种响应时间的滚动平均值。使用滚动平均值可以确定允许增加/减少的未完成请求总数。我不确定这是不是正确的方向

问题:
鉴于上述信息,我如何将未完成请求的总数保持在一个水平,以使所有作业花费的时间最少。

你在问什么?@i3arnon添加了一个更清晰的问题摘要。感谢您的回答,在循环内运行时,我如何调整MaxDegreeOfParallelism?此外,我还试图根据我的情况找出调整的标准和时间。我相信我有能力在上面的代码中调整运行计数。我更多的是寻找关于如何节流的逻辑,以及什么指标,如果这有意义的话。另外,如果不将ParallelOptions{改为and then.Rows为AsEnumerable,您的第一个代码块就不会编译。
List<DataTable> dataTables = new List<DataTable>();

Parallel.ForEach(newEntries.AsEnumerable(), new ParallelOptions { MaxDegreeOfParallelism = 2 }, row => {
   var request = RunRequest(row);
   lock(dataTables)
   {
        dataTables.Add(request);
   }
});
var runningTasks = 5;
//for loop to start 5 tasks.

while (taskList.count > 0)
{
    var indexer = Task.WaitAny(taskList);
    var myTask = taskList[indexer];
    taskList.RemoveAt(indexer);
    InterLocker.Decrement(ref runningTasks);
    var durationResult = myTask.Result();
    //do logic to determine if you need to start more.
    //when you start another use InterLocker.Increment(ref runningTasks);
}