在asp.net中限制异步任务,并限制N个成功任务
本文关键字:任务 成功 异步 asp net | 更新日期: 2023-09-27 18:13:48
我使用的是Asp.Net 4.5.1。我有一些任务要运行,这些任务调用web服务,有些可能会失败。我需要运行N个成功的任务,这些任务执行一些较轻的CPU工作,主要调用web服务,然后停止,我想节流。
例如,假设某个集合中有300个URL。我们需要在它们中的每一个上运行一个名为Task<bool> CheckUrlAsync(url)
的函数,并进行节流,这意味着,例如,只有5个"同时"运行(换句话说,在任何给定时间最多使用5个连接(。此外,我们只想执行N次(假设100次(成功操作,然后停止。
我读过这个和这个,但我仍然不确定什么是正确的方法。
你会怎么做?
- 假设ASP.Net
- 假设IO调用(对web服务器的http调用(,没有繁重的CPU操作
使用Semaphore slim。
var semaphore = new SemaphoreSlim(5);
var tasks = urlCollection.Select(async url =>
{
await semaphore.WaitAsync();
try
{
return await CheckUrlAsync(url);
}
finally
{
semaphore.Release();
}
};
while(tasks.Where(t => t.Completed).Count() < 100)
{
await.Task.WhenAny(tasks);
}
尽管我更喜欢使用Rx.Net来生成一些更好的代码。
using(var semaphore = new SemaphoreSlim(5))
{
var results = urlCollection.ToObservable()
.Select(async url =>
{
await semaphore.WaitAsync();
try
{
return await CheckUrlAsync(url);
}
finally
{
semaphore.Release();
}
}).Take(100).ToList();
}
好吧。。。这会很有趣。
public static class SemaphoreHelper
{
public static Task<T> ContinueWith<T>(
this SemaphoreSlim semaphore,
Func<Task<T>> action)
var ret = semaphore.WaitAsync()
.ContinueWith(action);
ret.ContinueWith(_ => semaphore.Release(), TaskContinuationOptions.None);
return ret;
}
var semaphore = new SemaphoreSlim(5);
var results = urlCollection.Select(
url => semaphore.ContinueWith(() => CheckUrlAsync(url)).ToList();
我需要补充的是,目前的代码仍将运行所有300个URL,只是会更快地返回。。。仅此而已。您需要将取消令牌添加到semaphore.WaitAsync(token)
以取消排队的工作。我再次建议使用Rx.Net。使用Rx.Net可以更容易地获得用于.Take(100)
的取消令牌。
试试这样的东西?
private const int u_limit = 100;
private const int c_limit = 5;
List<Task> tasks = new List<Task>();
int totalRun = 0;
while (totalRun < u_limit)
{
for (int i = 0; i < c_limit; i++)
{
tasks.Add(Task.Run (() => {
// Your code here.
}));
}
Task.WaitAll(tasks);
totalRun += c_limit;
}