我有一个客户端应用程序,可以运行大量的作业,大约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()
将从计数中减去。
我认为需要保持某种滚动平均响应时间。使用滚动平均值可以确定如何增加/减少允许的未完成请求总数。我不确定这是否是正确的方向。
问题 根据上述信息,如何将未完成请求的总数保持在一个级别,以便花费最少的时间用于所有工作。
答案 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);
}