Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 限制并行执行的异步方法的数量_C#_Multithreading_Asynchronous_Async Await_Task Parallel Library - Fatal编程技术网

C# 限制并行执行的异步方法的数量

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

我有一个关于异步方法并行执行的问题

我想限制将同时执行的异步方法的数量(限制对另一个系统的web请求的数量,这些请求实际上是通过异步方法发送的)

那么最好的方法是什么呢? 我通过使用Parallel找到了一个解决方案,并设置了DegreeOfParallelism,但我并不真正喜欢这个解决方案,因为它会阻止等于DOP(并行度)的线程数

下面是并行代码:

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