AFSDKによる複数アイテムのBulk読み込み(Bulk, Parallel)

以下Postで複数属性、複数タグへのBulkでの書き込み方法を紹介しました。

AFSDKによる複数属性、複数PIタグへのBulk書き込み

今回は複数アイテムのBulkでの読み込みをご紹介します。

なお、Bulkコールの他にParallelコールがあり、どちらが良いかはシチュエーションにより異なります。

以下KBを参考にしてください。(英語)

 

KB01216 - AF SDK Performance: Serial vs. Parallel vs. Bulk

https://techsupport.osisoft.com/Troubleshooting/KB/KB01216

 

BulkコールについてAFSDKのヘルプにサンプルコードがあります。

https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/abb5db84-4593-4937-b146-428622f719f2.htm

なお、listResultsに対してParallelで結果を取得することも可能です。(結果についてParallelを使用しているのでデータ取得はシングルのBulkコールです)

以下サンプルです。

PIServer myPIDataArchive = PIServer.FindPIServer("PIDataArchiveName"); 
// For tag search mask 
String TagNameMask = "testtag*"; 
//Start Time and End Time 
AFTimeRange timeRange = new AFTimeRange("*-10d", "*"); 
PIPointList pointList = new PIPointList(PIPoint.FindPIPoints(myPIDataArchive, TagNameMask)); 
int counter1 = 0; 
PIPagingConfiguration config = new PIPagingConfiguration(PIPageType.TagCount, 100); 
//Stopwatch Start 
Stopwatch sw1 = Stopwatch.StartNew(); 
//Bulk Call for pointList 
IEnumerable<AFValues> listResults = pointList.RecordedValues(timeRange, AFBoundaryType.Inside, "", true, config); 
Parallel.ForEach(listResults, afValues => 
{ 
 Console.WriteLine(afValues.PIPoint);
 foreach (AFValue value in afValues) 
 { 
 counter1 += 1;
 //Console.WriteLine(value.PIPoint + ":" + value.Timestamp.LocalTime + " : " + value.Value.ToString());
 } 
}); 
//Stopwatch Stop 
sw1.Stop(); 
 
//Write results 
Console.WriteLine("Bulk Call Results"); 
Console.WriteLine("Event number : " + counter1); 
Console.WriteLine("Bulk Time : " + sw1.Elapsed.TotalSeconds); 

Parallelを使用する場合、上記コードに付随して以下で使用できます。

//Parallel 
int counter2 = 0; 
//Stopwatch Start 
Stopwatch sw2 = Stopwatch.StartNew(); 
//Parallel call for pointList 
Parallel.ForEach(pointList, new ParallelOptions { MaxDegreeOfParallelism = 8 }, piPoint => 
{ 
 var afValues = piPoint.RecordedValues(timeRange, AFBoundaryType.Interpolated, null, false); 
 Console.WriteLine(piPoint.Name);
 foreach (AFValue value in afValues) 
 { 
 counter2 += 1;
 //Console.WriteLine(value.PIPoint + ":" + value.Timestamp.LocalTime + " : " + value.Value.ToString());
 } 
}); 
//StopStopwatch 
sw2.Stop(); 
//Write results 
Console.WriteLine("Parallel Call Results"); 
Console.WriteLine("Event number : " + counter2); 
Console.WriteLine("Parallel Time : " + sw2.Elapsed.TotalSeconds); 

KBにも記載がありますが、複数アイテムを取得する場合、シングルスレッドでループすると遅くなってしまいます。

Parallelを使用する際は終了が同期されているわけではないので、アプリケーション側で同期などは対処する必要があり、コードが複雑になるケースがある点はご注意ください。

例えばファイル書き出しなどする場合、Parallel.ForEach内では複数アクセスになるため、書き出せません。

比較すると、Bulkの方がコードは書きやすいかと思います。

Parents
  • AFテンプレートからデータを抽出して期間・インターバルを指定して内挿値を取り出すサンプルを作ってみました。

    ご参考までに

     

     static void Main(string[] args)
    
    
     // AFサーバー・AFデータベースへの接続 
     PISystems myPISystems = new PISystems();
     PISystem myPISystem = myPISystems["AFサーバー"];
     myPISystem.Connect();
     AFDatabase myDB = myPISystem.Databases["AFデータベース"];
     //結果書き出し先のパス指定
     var writer = new StreamWriter(@"C:\AFout\afoutresult2.txt");
     //該当エレメントテンプレートの指定
     AFElementSearch search = new AFElementSearch(myDB, "", "Template:'エレメントテンプレート名'");
     List<AFElement> listElements = new List<AFElement>();
     AFAttributeList attributes = new AFAttributeList();
     //エレメントテンプレート内の該当属性の指定
     foreach (var atr in search.FindElements(fullLoad: true))
     {
     attributes.Add(atr.Attributes["属性1"]);
     }
     //期間・インターバルの指定
     AFTimeRange timerange = new AFTimeRange("t-100d", "t");
     TimeSpan TM = new TimeSpan(0, 1, 0);
     AFTimeSpan interval = new AFTimeSpan(TM);
     Console.Write(interval);
     //config設定
     PIPagingConfiguration config = new PIPagingConfiguration(PIPageType.TagCount, 400);
     int counter1 = 0;
     
     TextWriter writerSync = TextWriter.Synchronized(writer) ;
     //stopwatchの開始
     Stopwatch sw1 = Stopwatch.StartNew();
     //リストのバルクコール 
     IEnumerable<AFValues> listResults = attributes.Data.InterpolatedValues(timerange, interval, "", false, config);
     Parallel.ForEach(listResults, afValues =>
     {
     Console.WriteLine(afValues.PIPoint);
     foreach (AFValue value in afValues)
     {
     counter1 += 1;
     //writerSync.WriteLine(value.PIPoint + ":" + value.Timestamp.LocalTime + " : " + value.Value.ToString());  }
     });
     //Stopwatchの停止 
     sw1.Stop();
     //結果の書き出し 
     writer.WriteLine("Event number : " + counter1, true);
     writer.WriteLine("Bulk Time : " + sw1.Elapsed.TotalSeconds, true);
     writer.Close();
     }
    
    

Reply
  • AFテンプレートからデータを抽出して期間・インターバルを指定して内挿値を取り出すサンプルを作ってみました。

    ご参考までに

     

     static void Main(string[] args)
    
    
     // AFサーバー・AFデータベースへの接続 
     PISystems myPISystems = new PISystems();
     PISystem myPISystem = myPISystems["AFサーバー"];
     myPISystem.Connect();
     AFDatabase myDB = myPISystem.Databases["AFデータベース"];
     //結果書き出し先のパス指定
     var writer = new StreamWriter(@"C:\AFout\afoutresult2.txt");
     //該当エレメントテンプレートの指定
     AFElementSearch search = new AFElementSearch(myDB, "", "Template:'エレメントテンプレート名'");
     List<AFElement> listElements = new List<AFElement>();
     AFAttributeList attributes = new AFAttributeList();
     //エレメントテンプレート内の該当属性の指定
     foreach (var atr in search.FindElements(fullLoad: true))
     {
     attributes.Add(atr.Attributes["属性1"]);
     }
     //期間・インターバルの指定
     AFTimeRange timerange = new AFTimeRange("t-100d", "t");
     TimeSpan TM = new TimeSpan(0, 1, 0);
     AFTimeSpan interval = new AFTimeSpan(TM);
     Console.Write(interval);
     //config設定
     PIPagingConfiguration config = new PIPagingConfiguration(PIPageType.TagCount, 400);
     int counter1 = 0;
     
     TextWriter writerSync = TextWriter.Synchronized(writer) ;
     //stopwatchの開始
     Stopwatch sw1 = Stopwatch.StartNew();
     //リストのバルクコール 
     IEnumerable<AFValues> listResults = attributes.Data.InterpolatedValues(timerange, interval, "", false, config);
     Parallel.ForEach(listResults, afValues =>
     {
     Console.WriteLine(afValues.PIPoint);
     foreach (AFValue value in afValues)
     {
     counter1 += 1;
     //writerSync.WriteLine(value.PIPoint + ":" + value.Timestamp.LocalTime + " : " + value.Value.ToString());  }
     });
     //Stopwatchの停止 
     sw1.Stop();
     //結果の書き出し 
     writer.WriteLine("Event number : " + counter1, true);
     writer.WriteLine("Bulk Time : " + sw1.Elapsed.TotalSeconds, true);
     writer.Close();
     }
    
    

Children
No Data