使用线程安全变量与并行for循环C#

使用线程安全变量与并行for循环C#

问题描述:

这是我第一次工作woth一个并行for循环,我理解的基本知识,你可以看到我的代码如下,但我不理解如何使内部变量循环线程安全。使用线程安全变量与并行for循环C#

我下面的文章在https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-write-a-parallel-for-loop-with-thread-local-variables

目前,我不断得到错误为:序列包含在我的计算类中没有的元素时,它正在执行对数据的计算。我是否缺少一些简单的东西来使所有线程安全?

更新:我添加了Calculations类的所有相关代码,其中显示了一个方法作为返回常量的示例。Sequence没有包含任何元素异常,并且目前为止我尝试修复此问题(异常仍在进行中)

更新2:我在我的代码中添加了自定义类,它应该允许它现在编译。

public static async Task Test() 
    { 
     Vector<double> vectorArrayBuy = null; 
     Vector<double> vectorArraySell = null; 
     Calculations calcTemp = null; 

     try 
     { 
      using (financeEntities context = new financeEntities()) 
      { 
       List<string> symbolList = new List<string>(); 
       symbolList = GetStockSymbols("nasdaq"); 

       foreach (string symbol in symbolList) 
       { 
        var query = await context.DailyStockDatas.Where(i => i.Symbol == symbol && i.Market == "nasdaq").ToListAsync(); 
        if (query.Count >= 200) 
        { 
         List<MultipleRegressionInfo> listMRInfo = new List<MultipleRegressionInfo>(); 
         Calculations calc = new Calculations(query, j); 
         calcTemp = calc; 

         Parallel.For(0, 200, j => 
         { 
          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(); 
          IEnumerable<double> value; 

          value = calc.ListCalculationData.Select(i => i.WilliamsR); 
          MultipleRegressionInfo r1 = Rn(value, vectorArrayBuy, nameof(name.WilliamsR), j, calc); 
          listMRInfo.Add(r1); 
         }); 

class Calculations 
{ 
    public List<DailyStockData> Data { get; set; } 
    public ConcurrentBag<CalculationData> ListCalculationData { get; set; } 

    public Calculations(List<DailyStockData> dailyData, int days) 
    { 
     lock (thisLock) 
     { 
      Data = dailyData; 

      // initiate the data 
      ListCalculationData = new ConcurrentBag<CalculationData>(); 

      for (int i = 0; i < Data.Count; i++) 
      { 
       var currentDate = Data.ElementAt(i).Date; 

       CalculationData calc = new CalculationData(currentCalcData); 
       calc.WilliamsR = CalculateWilliamsR(days, currentDate); 

       // add current calculator class to the list 
       ListCalculationData.Add(calc); 
      } 
     } 
    } 
public double CalculateWilliamsR(int days, DateTime startingDate) 
    { 
     double williamsR = 0; 
     double highestHigh = 0; 
     double currentClose = 0; 
     double lowestLow = 0; 

     try 
     { 
      highestHigh = FindMaxOrMin(days, startingDate, MaxOrMinType.HighestHigh); 
      lowestLow = FindMaxOrMin(days, startingDate, MaxOrMinType.LowestLow); 
      currentClose = (double)Data.Where(i => i.Date <= startingDate).Last().Close; 
      williamsR = -100 * ((highestHigh - currentClose)/(highestHigh - lowestLow)); 
     } 
     catch (Exception ex) 
     { 
      williamsR = 0; 
      Console.WriteLine(ex.Message); 
      Console.WriteLine(ex.StackTrace); 
     } 

     return williamsR; 
    } 

    public enum MaxOrMinType 
    { 
     HighestHigh, 
     LowestLow, 
     HighestClose, 
     LowestClose 
    } 

    public double FindMaxOrMin(int days, DateTime startingDate, MaxOrMinType type) 
    { 
     double maxMin = 0; 

     try 
     { 
      lock (thisLock) 
      { 
       switch (type) 
       { 
        // gets Sequence contains no elements exceptions at all of the below lines 
        case MaxOrMinType.HighestClose: 
         maxMin = (double)Data.Where(i => i.Date <= startingDate).Take(days).Max(i => i.Close); 
         break; 
        case MaxOrMinType.HighestHigh: 
         maxMin = (double)Data.Where(i => i.Date <= startingDate).Take(days).Max(i => i.High); 
         break; 
        case MaxOrMinType.LowestClose: 
         maxMin = (double)Data.Where(i => i.Date <= startingDate).Take(days).Min(i => i.Close); 
         break; 
        case MaxOrMinType.LowestLow: 
         maxMin = (double)Data.Where(i => i.Date <= startingDate).Take(days).Min(i => i.Low); 
         break; 
        default: 
         break; 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      maxMin = 0; 
      Console.WriteLine(ex.Message); 
      Console.WriteLine(ex.StackTrace); 
     } 

     return maxMin; 
    } 

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; } 
} 

enter image description here

+0

评论不适用于扩展讨论;这个对话已经[转移到聊天](http://chat.*.com/rooms/157820/discussion-on-question-by-user-3610374-using-a-thread-safe-variable-with-a-parall) 。 – Andy

序列不包含任何元素

对于这个问题,该问题是与(在它没有数据,即一组)服用Max一个empty set的。因此:

​​

失败。为了解决这个问题,将其更改为:

maxMin = Data.Where(i => i.Date <= startingDate).Take(days) 
    .OrderByDescending(z => z.Close) 
    .Select(z => (double?)z.Close) 
    .FirstOrDefault() ?? 0; 

OrderByDescending将确保最高Close列在第一位。 Select将确保返回Close值(或者如果根本没有条目,则返回null)。该?? 0null转换为0,如果没有匹配(变化0到任何价值是有道理的,你的目的。

一种不同的方法,考虑https://github.com/morelinq/MoreLINQ/issues/28

您需要更改每项在switch报表以类似的方式来解决这个问题(与Close是要么CloseHighLow,并与OrderByDescending是要么OrderByDescendingOrderBy)。

此外,在您的原始代码中,您正在执行Take而不是早期的OrderBy,但现在我会忽略它。

线程安全

在呼吁listMRInfo.Add的线程安全性方面 - 而不是做:

List<MultipleRegressionInfo> listMRInfo = new List<MultipleRegressionInfo>(); 

Parallel.For(0, 200, j => 
{ 
    // Code here 
    listMRInfo.Add(r1); 
}); 

考虑做:

var listMRInfo = Enumerable.Range(0, 200) 
    .AsParallel() 
    .Select(j => 
    { 
     // Code here 
     return r1; 
    }) 
    .ToList(); 

这将使你有相同的基本Parallel行为为For,但也允许您有一个List作为结果(以线程安全的方式)。