C#服务中的动态客户端限制

时间:2015-05-15 15:49:24

标签: c# async-await httprequest throttling

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

我正在努力减少所有工作的总时间。我注意到,如果我一次发出太多请求,响应时间会急剧增加,因为服务器基本上是DoSed。这将使所有工作的总数增加。我一直在使用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());

我知道throttler.Release();可以传递不同的数字,以一次增加未完成请求的总数,并且在没有Wait()的情况下调用Release()将从计数中减去。

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

问题 根据上述信息,如何将未完成请求的总数保持在一个级别,以便花费最少的时间用于所有工作。

1 个答案:

答案 0 :(得分:-1)

List<DataTable> dataTables = new List<DataTable>();

Parallel.ForEach(newEntries.AsEnumerable(), new ParallelOptions { MaxDegreeOfParallelism = 2 }, row => {
   var request = RunRequest(row);
   lock(dataTables)
   {
        dataTables.Add(request);
   }
});

现在您可以调整MaxDegreeOfParallelism //我不理解您希望在任务运行时动态更改此内容。

我会告诉你过去的经验,当我们尝试允许用户在使用信号量时正在运行的线程数量更改时,我想跳到移动的卡车前面。这是在TPL之前回来的。

创建未启动任务的列表。启动所需的任务数,例如5开始。每个任务都可以从头到尾返回一个持续时间,以便您可以使用它来定义油门逻辑。现在只需用waitany作为块来循环任务。

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);
}