【问题标题】:Cannot convert from 'oncurrentBag<T>' to 'Func<ConcurrentBag<T>>'无法从“oncurrentBag<T>”转换为“Func<ConcurrentBag<T>>”
【发布时间】:2023-04-02 16:47:01
【问题描述】:

我正在尝试使用并行 For 循环来帮助我加快处理器密集型计算,然后将这些计算添加到线程安全列表中,在 for 循环完成后我可以访问该列表,以便我可以访问数据。我按照https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-write-a-parallel-for-loop-with-thread-local-variables的示例进行操作

我在粗体行中遇到编译时错误,由于我是多线程新手,如果您能指出我所犯的任何错误,我将不胜感激,以便我可以从这个错误中吸取教训。

public static async Task Test()
    {
        Vector<double> vectorArrayBuy = null;
        Vector<double> vectorArraySell = null;
        ConcurrentBag<DailyStockData> query;

        query = new ConcurrentBag<DailyStockData>();
        ConcurrentBag<MultipleRegressionInfo> listMRInfo = new ConcurrentBag<MultipleRegressionInfo>();                
        Calculations calcTemp = new Calculations();

        **Parallel.For<ConcurrentBag<MultipleRegressionInfo>>(0, 200, (listMRInfo) = new ConcurrentBag<MultipleRegressionInfo>(), (j, loop, listMRInfoLocal) =>**
        {
            int k = Convert.ToInt32(j);
            Calculations calc = new Calculations(query, k);
            var targetValueBuy = calc.ListCalculationData.Select(i => i.MRTargetValueBuy).ToList();
            var targetValueSell = calc.ListCalculationData.Select(i => i.MRTargetValueSell).ToList();
            vectorArrayBuy = CreateVector.Dense(targetValueBuy.ToArray());
            vectorArraySell = CreateVector.Dense(targetValueSell.ToArray());
            var name = calc.ListCalculationData.First();
            ConcurrentBag<double> value;

            value = new ConcurrentBag<double>(calc.ListCalculationData.Select(i => i.WilliamsR));
            MultipleRegressionInfo r1 = Rn(value, vectorArrayBuy, nameof(name.WilliamsR), k, calc);
            listMRInfoLocal.Add(r1);
        calcTemp = calc;

            return listMRInfoLocal;
        },
        (variable) => listMRInfo = variable
        );
listMRInfo = new ConcurrentBag<MultipleRegressionInfo>(listMRInfo.OrderByDescending(i => i.RSquared).DistinctBy(i => i.ValueName).ToList()); // trying to access this data after parallel for loop completes

public class DailyStockData
{
    public DailyStockData();

    public int ID { get; set; }
    public string Symbol { get; set; }
    public string Market { get; set; }
    public DateTime Date { get; set; }
    public decimal Open { get; set; }
    public decimal High { get; set; }
    public decimal Low { get; set; }
    public decimal Close { get; set; }
    public decimal AdjustedClose { get; set; }
    public long Volume { get; set; }
}

public class CalculationData
{
    public CalculationData(CalculationData calcData)
    {
        Date = calcData.Date;
        Open = calcData.Open;
        High = calcData.High;
        Low = calcData.Low;
        Close = calcData.Close;
        AdjustedClose = calcData.AdjustedClose;
        Volume = calcData.Volume;
        WilliamsR = calcData.WilliamsR;
}

    public CalculationData() { }

    public DateTime Date { get; set; }
    public double Open { get; set; }
    public double High { get; set; }
    public double Low { get; set; }
    public double Close { get; set; }
    public double AdjustedClose { get; set; }
    public double Volume { get; set; }
    public double WilliamsR { get; set; }
}

【问题讨论】:

  • 这听起来像是编译时错误,而不是异常。如果您提供minimal reproducible example,会更容易为您提供帮助。
  • @JonSkeet 我添加了我使用的自定义类,但我不知道如何在不让你访问我的数据库的情况下让它为你运行。你有什么建议?
  • 我建议您将其简化为 minimal 示例。我非常怀疑那里的大部分代码都与重现问题有关。

标签: c# multithreading parallel-processing task-parallel-library


【解决方案1】:

看起来您正在尝试使用比您需要的更复杂的 Parallel.For 函数重载。 listMRinfo 是一个并发类,因此在 for 循环的每次迭代中直接访问该变量是安全的。

Parallel.For<ConcurrentBag<MultipleRegressionInfo>>(0, 200, (index) =>
{
    // ...
    listMRInfo.Add(r1);
});

另一方面,如果没有进行某种锁定,则不应在循环的每次迭代中更新对calcTemp 的引用。即使使用锁定,我也不认为您应该存储循环的 one 迭代中的值。这是一个并行 foreach,因此循环完成后,您无法保证calcTemp 的值来自哪个迭代

【讨论】:

  • 你建议我如何处理 calcTemp 变量?
  • 我不能说没有看到它是如何使用的。您是否希望这是循环的最后一次计算?如果是这样,我会在 循环运行后创建它 - calcTemp = new Calculations(query, 200)
  • 好吧,我觉得自己像个白痴。我一直试图让这个并行 for 循环整天工作,但我认为它不起作用,因为我需要按顺序执行我的计算,并且我相信并行 for 循环适用于具有随机顺序的项目。无论如何我可以获得并行计算的力量并按顺序完成还是我搞砸了?
  • 并行运行意味着计算必须产生相同的结果,无论每次迭代的执行顺序如何。如果您的计算是顺序的,那么您可能无法并行运行它
  • 恐怕我的大部分计算都是连续的,所以我没有任何选项可以让计算运行得更快吗?
【解决方案2】:

你的问题在这里:

... (listMRInfo) = new ConcurrentBag<MultipleRegressionInfo>() ...

没有Parallel.For的重载,其第三个参数接受T,最佳匹配是这个:

Parallel.For<TLocal> Method (Int32, Int32, Func<TLocal>, Func<Int32, ParallelLoopState, TLocal, TLocal>, Action<TLocal>)

而且,正如错误所说,TLocal 不能隐式转换为 Func&lt;TLocal&gt;。由于该参数没有意义,因为 listMRInfo 已经分配,​​您应该这样做:

Parallel.For<ConcurrentBag<MultipleRegressionInfo>>(0, 200, (j, loop, listMRInfoLocal) => 
{
    ... 
}

【讨论】:

  • 当我将我的代码更改为它现在显示方法没有重载 For 需要 4 个参数
  • 那你做错了,我的回答只有3个参数。
  • 我所做的只是复制并粘贴您所写的内容。我删除了 ConcurrentBag> 并消除了错误,但我只是将代码改回了简单的并行 for 循环,我又回到了导致我尝试这些新方法的相同错误。 C# 中的多线程是我存在的祸根,我只是觉得我在绕圈子:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-31
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多