public static IEnumerableAsync <TResult> Throttle <TSource, TResult, TThrottle>(this IEnumerable <TSource> enumerable, Func <TSource, IManagePerformance <TThrottle>, Task <TResult> > selectKey, int desiredRunCount = 1, ILogger log = default(ILogger)) { var throttler = new PerformanceManager <TThrottle>(desiredRunCount, log); var runList = new List <Task>(); return(enumerable .Select( item => throttler.RunTask(() => selectKey(item, throttler))) .AsyncEnumerable()); }
/// <summary> /// Read remarks. /// </summary> /// <typeparam name="TSource"></typeparam> /// <typeparam name="TResult"></typeparam> /// <typeparam name="TThrottle"></typeparam> /// <param name="enumerable"></param> /// <param name="selectKey"></param> /// <param name="initialBandwidth"></param> /// <param name="tag"></param> /// <returns></returns> /// <remarks> /// Throttling can only slow down iteration. Throttling cannot accelerate/force iteration. Therefore, unless the /// calling method requests the tasks in the returned enumeration faster than the tasks' Results are awaited, /// the iteration will be sequention and Throttle will have a negligable effect. More specifically, /// be sure to call a method such as Prespool, Batch, Array, etc before calling Await on the throttled IEnumerableAsync<Task<TResult>>. /// </remarks> public static IEnumerableAsync <Task <TResult> > Throttle <TSource, TResult, TThrottle>(this IEnumerableAsync <TSource> enumerable, Func <TSource, IManagePerformance <TThrottle>, Task <TResult> > selectKey, int desiredRunCount = 1, ILogger log = default(ILogger)) { var logScope = log.CreateScope($"Throttle[{Guid.NewGuid()}]"); var throttler = new PerformanceManager <TThrottle>(desiredRunCount, logScope); return(enumerable .Batch() .SelectMany( items => { return items .Select(item => throttler.RunTask(() => selectKey(item, throttler))); })); }