可枚举的foreach扩展

时间:2018-11-08 13:55:11

标签: c# ienumerable

我创建了对Enumerable的扩展以快速执行动作,因此我列出了该方法,并进行了循环,如果对象在特定时间内执行该方法,我会返回, 现在,我想使输出通用,因为方法输出将有所不同,有关如何处理的任何建议

这个IEnumerable进程,就像负载均衡一样,如果第一个没有响应,第二个应该响应,我想返回输入Action的输出

Plumber Related

此代码的运行方式

public static class EnumerableExtensions
{
    public static void ForEach<T>(this IEnumerable<T> source, Action action, int timeOut)
    {            
        foreach (T element in source)
        {
            lock (source)
            {
                // Loop for all connections and get the fastest responsive proxy 
                foreach (var mxAccessProxy in source)
                {
                    try
                    {
                        // check for the health 
                        Task executionTask = Task.Run(action);
                        if (executionTask.Wait(timeOut))
                        {
                            return  ;
                        }
                    }
                    catch
                    {
                        //ignore 
                    }

                }
            }
        }
    }
}

1 个答案:

答案 0 :(得分:3)

  

这将提高性能和代码可读性

不,它绝对不会:)此外,此代码还会带来更多问题,例如冗余锁定或吞咽异常,但实际上并不能并行执行代码。

似乎您想使用某种代理对象来为您的Action获得最快的通话。您需要异步运行Tasks,而不是.Wait()

类似的事情可能对您有帮助:

public static class TaskExtensions
{
    public static TReturn ParallelSelectReturnFastest<TPoolObject, TReturn>(this TPoolObject[] pool,
        Func<TPoolObject, CancellationToken, TReturn> func, 
        int? timeout = null)
    {
        var ctx = new CancellationTokenSource();

        // for every object in pool schedule a task
        Task<TReturn>[] tasks = pool
            .Select(poolObject =>
            {
                ctx.Token.ThrowIfCancellationRequested();
                return Task.Factory.StartNew(() => func(poolObject, ctx.Token), ctx.Token);
            })
            .ToArray();

       // not sure if Cast is actually needed, 
       // just to get rid of co-variant array conversion
       int firstCompletedIndex = timeout.HasValue
            ? Task.WaitAny(tasks.Cast<Task>().ToArray(), timeout.Value, ctx.Token)
            : Task.WaitAny(tasks.Cast<Task>().ToArray(), ctx.Token);

        // we need to cancel token to avoid unnecessary work to be done
        ctx.Cancel();

        if (firstCompletedIndex == -1) // no objects in pool managed to complete action in time
            throw new NotImplementedException(); // custom exception goes here

        return tasks[firstCompletedIndex].Result;
    }
}

现在,您可以使用此扩展方法在任何对象池上调用特定操作并获取第一个执行结果:

var pool = new[] { 1, 2, 3, 4, 5 };
var result = pool.ParallelSelectReturnFastest((x, token) => { 
    Thread.Sleep(x * 200); 
    token.ThrowIfCancellationRequested();
    Console.WriteLine("calculate");
    return x * x; 
}, 100);    
Console.WriteLine(result);    

它输出:

  

计算   1

因为第一个任务将在200毫秒内完成工作,将其返回,并且所有其他任务将通过取消令牌被取消。

在您的情况下,它将类似于:

var actionResponse = proxiesList.ParallelSelectReturnFastest((proxy, token) => {
    token.ThrowIfCancellationRequested();
    return proxy.SomeAction();        
});

有些事情要提:

  • 确保操作安全。您不能依靠其中有多少实际会真正执行您的操作。如果此操作为CreateItem,那么最终可以通过不同的代理创建许多项目
  • 不能保证您将并行执行所有这些操作,因为由TPL选择最佳数量的正在运行的任务
  • 我已经以老式的TPL方式实现了,因为您的原始问题包含了它。如果可能,您需要切换到异步/等待-在这种情况下,您的Func将返回任务,并且您需要使用await Task.WhenAny(tasks)而不是Task.WaitAny()