Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/32.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# 有没有办法在ASP.NET Web API应用程序中全局限制并行任务的数量?_C#_Asp.net_Async Await_Task - Fatal编程技术网

C# 有没有办法在ASP.NET Web API应用程序中全局限制并行任务的数量?

C# 有没有办法在ASP.NET Web API应用程序中全局限制并行任务的数量?,c#,asp.net,async-await,task,C#,Asp.net,Async Await,Task,我有一个ASP.NET 5 Web API应用程序,其中包含一个方法,该方法从列表中获取对象,并向服务器发出HTTP请求,每次5个,直到所有请求完成。这是使用一个信号量lim、一个列表()、并等待任务完成的。WhenAll(),类似于下面的示例代码段: 公共异步任务DoStuff(列表输入数据) { const int maxDegreeOfParallelism=5; var tasks=新列表(); 使用var节流器=新信号量lim(maxDegreeOfParallelism); fore

我有一个ASP.NET 5 Web API应用程序,其中包含一个方法,该方法从
列表中获取对象,并向服务器发出HTTP请求,每次5个,直到所有请求完成。这是使用一个
信号量lim
、一个
列表()
、并等待
任务完成的。WhenAll()
,类似于下面的示例代码段:

公共异步任务DoStuff(列表输入数据)
{
const int maxDegreeOfParallelism=5;
var tasks=新列表();
使用var节流器=新信号量lim(maxDegreeOfParallelism);
foreach(inputData中的var输入)
{
添加(ExecHttpRequestAsync(输入,节流器));
}
List resposnes=wait Task.WhenAll(tasks).configurewait(false);
回应;
}
专用异步任务ExecHttpRequestAsync(输入,信号量限制)
{
wait throttler.WaitAsync().ConfigureWait(false);
尝试
{
使用var request=newhttprequestmessage(HttpMethod.Post)https://foo.bar/api");
request.Content=newstringcontent(JsonConvert.SerializeObject(input,Encoding.UTF8,“application/json”);
var response=await HttpClientWrapper.SendAsync(请求).ConfigureAwait(错误);
var responseBody=await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObject=JsonConvert.DeserializeObject(responseBy);
返回响应对象;
}
最后
{
节流器释放();
}
}
这很好,但是我希望限制在整个应用程序中并行执行的任务总数,以允许此应用程序的扩展。例如,如果同时传入50个对我的API的请求,这将启动最多250个并行运行的任务。如果我想限制总数在任何给定时间执行的任务的数量,比如说100,是否有可能完成此任务?可能通过
队列
?框架是否会自动防止执行太多任务?或者我是否以错误的方式处理此问题,是否需要将传入的请求排入我的应用程序队列

如果我想将在任何给定时间执行的任务总数限制在100个,那么有可能实现这一点吗

您想要的是限制所谓的的。您可以控制它管理的任务的
最大一致性级别
。我建议实现一个类似队列的对象,跟踪传入请求和当前工作请求,并在消耗更多之前等待当前请求完成。下面的信息可能仍然相关

任务调度器负责如何确定任务的优先级,并负责跟踪任务,确保任务至少最终完成

它这样做的方式实际上与您提到的非常相似,通常任务调度器处理任务的方式是FIFO(先进先出)模型,与任务调度器的工作方式非常相似()

框架会自动防止执行过多的任务吗

默认情况下,使用大多数应用程序创建的TaskScheduler默认值为
int.MaxValue
MaximumConcurrencyLevel
。因此理论上

事实上,任务数量实际上没有限制(至少在默认的
TaskScheduler
)对于您的案例场景来说可能没什么大不了的

任务分为两种类型,至少在如何分配给可用线程池时是这样

在不太详细的情况下,其工作方式是如果任务创建其他任务,则这些新任务是父任务队列(本地队列)的一部分。父任务生成的任务仅限于父任务的线程池。()

如果一个任务不是由另一个任务创建的,那么它是一个顶级任务,并被放入全局队列中。这些任务通常会被分配自己的线程(如果可用),如果一个线程不可用,它将在FIFO模型中处理,如上所述,直到它的工作可以完成为止


这一点很重要,因为尽管您可以限制使用
任务调度器发生的并发量,但这一点可能并不重要——例如,如果您有一个标记为长时间运行并负责处理传入请求的顶级任务。这将很有帮助,因为所有任务都是由该顶级任务生成的-级别任务将是该任务的本地队列的一部分,因此不会对线程池中的所有可用线程进行垃圾邮件处理。

我假设代码是固定的,即
任务。Run
被删除,并且
WaitAsync
/
释放
被调整为限制HTTP调用,而不是
列表。添加

我希望在整个应用程序中限制并行执行的任务总数,以允许扩展此应用程序

这对我来说没有意义。限制你的任务会限制你的扩展

例如,如果同时传入50个对我的API的请求,那么最多会启动250个并行运行的任务

同时,当然可以,但不能并行。需要注意的是,这些线程不是250个线程,它们也不是等待空闲线程池线程运行的250个CPU限制的操作。这些是承诺任务,不是委托任务,因此它们根本不在线程上“运行”。内存中只有250个对象

如果我想将在任何给定时间执行的任务总数限制在100个,那么有可能实现这一点吗

由于(这类)任务只是内存中的对象,因此不需要限制它们,就像您需要限制
字符串
s或
列表
s的数量一样。在确实需要的地方应用节流;例如。
private const int maxConcurrencyGlobal = 100;
private static SemaphoreSlim globalThrottler
    = new SemaphoreSlim(maxConcurrencyGlobal, maxConcurrencyGlobal);

public async Task<ResponseObj[]> DoStuffAsync(IEnumerable<Input> inputData)
{
    const int maxConcurrencyPerRequest = 5;
    var perRequestThrottler
        = new SemaphoreSlim(maxConcurrencyPerRequest, maxConcurrencyPerRequest);

    Task<ResponseObj>[] tasks = inputData.Select(async input =>
    {
        await perRequestThrottler.WaitAsync();
        try
        {
            await globalThrottler.WaitAsync();
            try
            {
                return await ExecHttpRequestAsync(input);
            }
            finally { globalThrottler.Release(); }
        }
        finally { perRequestThrottler.Release(); }
    }).ToArray();
    return await Task.WhenAll(tasks);
}
private const int maxConcurrencyGlobal = 100;
private static SemaphoreSlim globalThrottler
    = new SemaphoreSlim(maxConcurrencyGlobal, maxConcurrencyGlobal);

public async Task<ResponseObj[]> DoStuffAsync(IEnumerable<Input> inputData)
{
    const int maxConcurrencyPerRequest = 5;
    var perRequestThrottler
        = new SemaphoreSlim(maxConcurrencyPerRequest, maxConcurrencyPerRequest);

    var tasks = new List<Task<ResponseObj>>();
    foreach (var input in inputData)
    {
        await perRequestThrottler.WaitAsync();
        await globalThrottler.WaitAsync();
        Task<ResponseObj> task = Run(async () =>
        {
            try
            {
                return await ExecHttpRequestAsync(input);
            }
            finally
            {
                try { globalThrottler.Release(); }
                finally { perRequestThrottler.Release(); }
            }
        });
        tasks.Add(task);
    }
    return await Task.WhenAll(tasks);

    static async Task<T> Run<T>(Func<Task<T>> action) => await action();
}