2017-10-29 3 views
-1

Dies ist das erste Mal, dass ich mit einer parallelen for-Schleife arbeite und die Grundlagen verstehe, wie Sie mit meinem Code unten sehen können, aber ich verstehe nicht, wie man die Variablen einbaut der Schleifenfaden sicher.Verwenden einer threadsicheren Variablen mit einer parallelen for-Schleife C#

Ich folge den Artikel zu einem https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-write-a-parallel-for-loop-with-thread-local-variables

Ich bin derzeit konstanten Fehler für immer: Sequenz enthält keine Elemente in meinen Berechnungen Klasse, wenn es um die Berechnungen auf den Daten durchgeführt wird. Fehle ich etwas Einfaches, um das alles threadsicher zu machen?

UPDATE: Ich habe den gesamten relevanten Code für die Calculations-Klasse hinzugefügt, der eine Methode als Beispiel zeigt, die konstant zurückgibt. Sequence enthält keine Element-Exceptions und was ich bisher getan habe, um das Problem zu beheben (Ausnahmen laufen noch))

UPDATE 2: Ich habe die benutzerdefinierten Klassen in meinem Code hinzugefügt, die es jetzt kompilieren sollten.

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

Kommentare sind nicht für längere Diskussion; Diese Konversation wurde [in den Chat verschoben] (http://chat.stackoverflow.com/rooms/157820/discussion-on-question-by-user3610374-using-a-thread-safe-variable-with-a-parall) . – Andy

Antwort

2

Sequence

Für dieses Problem keine Elemente enthält, ist das Problem mit der Einnahme eines Maxempty set (d.h. ein Satz ohne Daten darin). Also:

maxMin = (double)Data.Where(i => i.Date <= startingDate).Take(days).Max(i => i.Close); 

schlägt fehl. Um dies zu lösen, ändern Sie es zu:

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

Die OrderByDescending wird dafür sorgen, dass die höchste Close zuerst genannt. Die Select stellt sicher, dass der Wert Close zurückgegeben wird (oder null, wenn überhaupt keine Einträge vorhanden sind). Die ?? 0 die null auf 0 konvertieren, wenn es keine Übereinstimmungen (ändern 0 zu werden, was auch immer Wert sinnvoll für Ihre Zwecke.

Für einen anderen Ansatz, betrachten https://github.com/morelinq/MoreLINQ/issues/28.

Sie werden jeweils ändern müssen die switch Aussagen in ähnlicher Weise das Problem zu lösen (mit Close entweder Close oder High oder Low zu sein, und mit OrderByDescending entweder OrderByDescending oder OrderBy).

Außerdem ist es seltsam in Ihrem ursprünglichen Code, dass Sie eine Take ohne eine frühere OrderBy machten, aber ich werde das für jetzt ignorieren.

Thema Sicherheit

In Bezug auf die Thread-Sicherheit listMRInfo.Add des Aufrufs - und nicht tun:

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

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

in Erwägung ziehen:

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

Dies ermöglicht Sie haben die gleiche grundlegende Parallel Verhalten wie For, aber auch Sie können eine List als Ergebnis haben (auf eine Thread-sichere Weise).

Verwandte Themen