Parallel.ForEach不在VS2013中编译,但在VS2015中有效

时间:2017-07-02 21:23:10

标签: c# visual-studio-2013 visual-studio-2015 parallel.foreach

我使用此example创建分区,并且在我的VS2015应用中完美运行。我尝试使用4.5.2框架将代码移动到VS2013,现在这段代码出错:

  

VS2013 12.0.40629.00更新5

body: (source, state, local) => 

  

错误5委托' System.Func< System.Tuple< long,long&gt ;,System.Threading.Tasks. ParallelLoopState,lo ng,AnonymousType#1,A nonymousType#1>&#39 ;不带3个参数

我发现了这个问题:Whats wrong in this Parallel.For Code?非常相似。但它似乎并不是同样的问题。

建议的答案在2013年没有任何语法错误,但没有使用分区,所以我不确定如何使我的代码适应那个。建议添加三个参数,我的已有三个参数。

这是我的代码的简化版本:

public void NearLinkParallelGeneration(avl_range avl_pending)
{
    var parallelOptions = new ParallelOptions
    {
        MaxDegreeOfParallelism = Environment.ProcessorCount + 2
    };

    var partitions = Partitioner
                        .Create(
                            fromInclusive: avl_pending.begin,
                            toExclusive: avl_pending.end,
                            rangeSize: 100
                        )
                        .GetDynamicPartitions();

    Parallel.ForEach(
        source: partitions,
        parallelOptions: parallelOptions,
        localInit: () => 
        {
            NpgsqlConnection conn = new NpgsqlConnection(strConnection);
            NpgsqlCommand cmd = new NpgsqlCommand();

            conn.Open();

            return new { Connection = conn, Command = cmd };
        },
        body: (source, state, local) => -- HERE IS THE ERROR
        {
            return local;
        },
        localFinally: local =>
        {
            local.Connection?.Dispose();
            local.Command?.Dispose();
        }
    );

错误图片:https://i.stack.imgur.com/6Q5Ge.png

1 个答案:

答案 0 :(得分:1)

我没有安装VS2013,因此我无法重现您的问题。但是,似乎编译器对选择哪个重载感到困惑。

您要复制的代码使用ForEach()方法的Parallel.ForEach<TSource, TLocal> Method (IEnumerable<TSource>, ParallelOptions, Func<TLocal>, Func<TSource, ParallelLoopState, TLocal, TLocal>, Action<TLocal>)重载。

您收到的错误消息表明编译器为您的呼叫选择了Parallel.ForEach<TSource, TLocal> Method (IEnumerable<TSource>, ParallelOptions, Func<TLocal>, Func<TSource, ParallelLoopState, Int64, TLocal, TLocal>, Action<TLocal>)重载。也就是说,它希望代表不仅会收到sourcestatelocal值,还会收到当前项的index

目前缺乏在VS2013中测试代码的能力,我不完全确定为什么编译器选择了错误的重载。但我认为它可能与'Delegate 'System.Action' does not take 0 arguments.' Is this a C# compiler bug (lambdas + two projects)?中描述的问题有关。答案是,是的,它是编译器错误,因为延迟缓存导致编译器的重载元数据出错。

如果确实如此,您应该能够通过为lambda参数提供显式类型来解决此问题。不幸的是,在您的情况下,您使用TLocal类型参数的匿名类型。所以你没有这个选项,除非你愿意声明一个命名类型而不是匿名类型。

另一种选择是放弃并遵循编译器关于你调用过载的想法。再一次,我不能自己测试,但我希望这会有效:

Parallel.ForEach(
    source: partitions,
    parallelOptions: parallelOptions,
    localInit: () => 
    {
        NpgsqlConnection conn = new NpgsqlConnection(strConnection);
        NpgsqlCommand cmd = new NpgsqlCommand();

        conn.Open();

        return new { Connection = conn, Command = cmd };
    },
    body: (source, state, index, local) // just add the 'index' parameter
    {
        return local;
    },
    localFinally: local =>
    {
        local.Connection?.Dispose();
        local.Command?.Dispose();
    }
);