限制asp .net中的异步任务,限制N个成功任务

H.W*_*per 4 c# asp.net asynchronous

我正在使用Asp .Net 4.5.1.我有运行任务,调用Web服务,有些可能会失败.我需要运行N个成功的任务,这些任务执行一些轻微的CPU工作,主要是调用Web服务,然后停止,我想要限制.

例如,假设我们在某个集合中有300个URL.我们需要运行一个调用Task<bool> CheckUrlAsync(url)每个函数的函数,带有限制,这意味着,例如,"同时"只运行5次(换句话说,在任何给定时间最多使用5个连接).此外,我们只想执行N(假设100)成功操作,然后停止.

我读过这个和这个,我仍然不知道什么是做了正确的道路.

你会怎么做?

  1. 假设ASP .Net
  2. 假设IO调用(http调用web serice),没有繁重的CPU操作.

Aro*_*ron 6

使用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);
}
Run Code Online (Sandbox Code Playgroud)

虽然我更喜欢使用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();
}
Run Code Online (Sandbox Code Playgroud)

好的......这会很有趣.

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();
Run Code Online (Sandbox Code Playgroud)

我确实需要补充一点,现在的代码仍将运行所有300个URL,它只会更快地返回......这就是全部.您需要将取消令牌添加semaphore.WaitAsync(token)到取消排队的工作.我再次建议使用Rx.Net.它更容易使用Rx.Net来获取取消令牌.Take(100).