C# 限制并行执行的异步方法的数量
我有一个关于异步方法并行执行的问题 我想限制将同时执行的异步方法的数量(限制对另一个系统的web请求的数量,这些请求实际上是通过异步方法发送的) 那么最好的方法是什么呢? 我通过使用Parallel找到了一个解决方案,并设置了DegreeOfParallelism,但我并不真正喜欢这个解决方案,因为它会阻止等于DOP(并行度)的线程数 下面是并行代码:C# 限制并行执行的异步方法的数量,c#,multithreading,asynchronous,async-await,task-parallel-library,C#,Multithreading,Asynchronous,Async Await,Task Parallel Library,我有一个关于异步方法并行执行的问题 我想限制将同时执行的异步方法的数量(限制对另一个系统的web请求的数量,这些请求实际上是通过异步方法发送的) 那么最好的方法是什么呢? 我通过使用Parallel找到了一个解决方案,并设置了DegreeOfParallelism,但我并不真正喜欢这个解决方案,因为它会阻止等于DOP(并行度)的线程数 下面是并行代码: var results = dataProvider.GetResults(someIdParam); var aver
var results = dataProvider.GetResults(someIdParam);
var average = results.AsParallel().WithDegreeOfParallelism(5).Average(x =>
{
var t = GetSSIM(x);
t.Wait();
return t.Result;
});
因此,这将起作用并限制同时请求的数量,但会阻止5个线程
我最终写下了自己的方法:
public static async Task<IEnumerable<T2>> ProcessEachAsync<T1, T2>(IEnumerable<T1> src, Func<T1, Task<T2>> func, int dop)
{
var workers = new Task<T2>[Math.Min(dop, src.Count())]; //to make sure that we will not have nulls in workers collection
var result = new List<T2>();
int counter = 0;
int index = 0;
foreach(var element in src)
{
if (counter < dop)
index = counter++;
else
{
var ended = await Task.WhenAny(workers);
index = Array.FindIndex(workers, x => x == ended);
result.Add(ended.Result);
}
var t = func(element);
t.Start();
workers[index] = t;
}
Task.WaitAll(workers);
result.AddRange(workers.Select(x => x.Result));
return result;
}
public静态异步任务进程chasync(IEnumerable src、Func Func、int dop)
{
var-workers=new Task[Math.Min(dop,src.Count())];//确保workers集合中没有空值
var result=新列表();
int计数器=0;
int指数=0;
foreach(src中的var元素)
{
如果(计数器x==end);
结果.添加(结束.结果);
}
var t=func(元素);
t、 Start();
工人[指数]=t;
}
Task.WaitAll(工人);
AddRange(workers.Select(x=>x.result));
返回结果;
}
小心!!!!!这段代码还没有经过测试,有bug!!!!
但它解释了主要思想
因此,此解决方案将只阻止1个线程。也许有更简单的方法来实现我想要的?感谢@evk和我的同事帮助我解决了这个问题。 所以我用信号量lim实现了一个解决方案。它的缺点是它将所有数据转换为任务,但代码太漂亮了,我将不使用它:)
public静态异步任务进程chasync(IEnumerable src、Func Func、int dop)
{
使用(var semSlim=新信号量lim(dop))
{
var结果=新的ConcurrentBag();
Func getTask=async(x)=>
{
尝试
{
wait semSlim.WaitAsync();
var res=等待函数(x);
结果:添加(res);
}
最后
{
semSlim.Release();
}
};
wait Task.WhenAll(src.Select(x=>getTask(x));
返回结果;
}
}
小心!!!没有测试强>
谢谢大家 我认为stack overflow的code review版本更能解决这个问题,仅供参考,我认为您会得到更好的反馈,您可以使用
SemaphoreSlim
来限制该数量,例如:(以及在许多其他地方)。检查此处的速率限制:@Evk-是,信号量Lim非常适合您忘记处理信号量。另外,不需要“新任务”-lambda也可以是异步的。最后,也不需要并发bag-您可以从lambda返回结果('return wait func(x)')@Evk我根据您的评论进行了更改。现在这个答案代表了我最终得到的解决方案。谢谢
public static async Task<IEnumerable<T2>> ProcessEachAsync<T1, T2>(IEnumerable<T1> src, Func<T1, Task<T2>> func, int dop)
{
using (var semSlim = new SemaphoreSlim(dop))
{
var result = new ConcurrentBag<T2>();
Func<T1, Task> getTask = async (x) =>
{
try
{
await semSlim.WaitAsync();
var res = await func(x);
result.Add(res);
}
finally
{
semSlim.Release();
}
};
await Task.WhenAll(src.Select(x => getTask(x)));
return result;
}
}