亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

加快C#雙循環(huán)的速度效率的方法

 更新時間:2025年02月20日 08:38:55   作者:中游魚  
最近使用 C# 改寫以前編的一個程序,檢索數(shù)據(jù)賦值時,使用 FOR 循環(huán)結(jié)構(gòu),當數(shù)據(jù)量在9萬條時,計算量很大,導(dǎo)致很耗時,何況計算完成同時加載到 chart 和 dataGridView 圖表控件中(沒有使用第三方控件),于是百度了很多循環(huán)手段,本文介紹了加快C#雙循環(huán)的速度效率的方法

一、前言

最近使用 C# 改寫以前編的一個程序,檢索數(shù)據(jù)賦值時,使用 FOR 循環(huán)結(jié)構(gòu),當數(shù)據(jù)量在9萬條時,計算量很大,導(dǎo)致很耗時,何況計算完成同時加載到 chart 和 dataGridView 圖表控件中(沒有使用第三方控件),于是百度了很多循環(huán)手段。

二、多種循環(huán)的速度效率

2.1、常用循環(huán)速度效率對比

循環(huán)結(jié)構(gòu)體速度和效率
for(int i=0;i<n;i++){}對于已知次數(shù)的迭代,使用 for 循環(huán)通常是最快的。
foreach(string S in Data){}適用于遍歷集合,如數(shù)組或列表,但通常比 for 循環(huán)慢,因為它需要更多的間接訪問。
while
do-while
適用于不確定次數(shù)的迭代,但可能在性能上不如 for 循環(huán)。
Parallel.For
Parallel.ForEach
Parallel.Invoke
并行計算類,三個方法都會阻塞線程直到所有工作完成為止。僅當適用時可采用,否則出現(xiàn)意外錯誤。
Parallel.ForEach 比 Parallel.For 效率更高。
Parallel.Invoke 適合用于執(zhí)行大量且無返回值的場景;
Parallel.For 使用是無序的,適合帶索引的大量循環(huán)操作;
Parallel.ForEach 適合數(shù)組、集合、枚舉大數(shù)據(jù)集的循環(huán)執(zhí)行,執(zhí)行結(jié)果是無序的。

2.2、如何提高循環(huán)的速度效率

2.2.1、選擇合適的循環(huán)類型

循環(huán)的效率通常取決于多個因素,包括循環(huán)的類型、循環(huán)體內(nèi)的操作、以及循環(huán)的次數(shù)。選擇合適的循環(huán)類型很重要。

2.2.2、減少循環(huán)體內(nèi)的操作

循環(huán)體內(nèi)的操作越少,循環(huán)的效率越高。例如,避免在每次迭代中進行復(fù)雜的計算或方法調(diào)用。

2.2.3、使用局部變量而非頻繁訪問成員

如果循環(huán)體內(nèi)需要多次訪問對象的成員,最好將該成員的值存儲在局部變量中,這樣可以減少多次訪問成員的開銷。

2.2.4、避免在循環(huán)體內(nèi)進行不必要的對象創(chuàng)建或銷毀

每次迭代創(chuàng)建新對象會增加GC(垃圾回收)的壓力,降低性能。如果可能,考慮對象池技術(shù)或復(fù)用對象。

2.2.5、僅當適用時可采用并行處理

對于可以并行處理的計算任務(wù),使用 Parallel.For 或 PLINQ(Parallel LINQ)可以顯著提高性能,特別是當處理大量數(shù)據(jù)時。然而,并行處理需要謹慎使用,因為它會增加線程管理的開銷。

三、如何提高雙循環(huán)計算速度效率的編程實例

遵循上述循環(huán)原則,對于有序的數(shù)據(jù)集,通過多次測試各種循環(huán),采用的 for 雙循環(huán)。

Hypack RAW 數(shù)據(jù)中,實時采集的定位 POS 數(shù)據(jù)和 EC1 數(shù)據(jù)系列,時間和位置大部分不同步,但處于同一個航線軌跡上,通過各采集點的時間秒、坐標、水深,計算航行距離、航行速度,以計算插補 EC1 采集數(shù)據(jù)所在定位坐標。

POS 數(shù)據(jù)有時間、定位東和北坐標數(shù)組,POSTime[]、POSEast[]、POSNorth[] 數(shù)據(jù)長度一致。
EC1 數(shù)據(jù)有時間、水深數(shù)組,EC1Time[]、EC1WaterDepth[] 數(shù)據(jù)長度一致。

POS 和 EC1 數(shù)據(jù)個數(shù)不對等。

還要根據(jù) FIX 和 EC1 數(shù)據(jù),插補 FIX 采集數(shù)據(jù)點的水深,這里就不描述。

Hypack RAW 數(shù)據(jù)節(jié)選如下:

POS 0 37410.599 626291.650 3216635.552
QUA 0 37410.599 7 3.000 1.000 8.000 2.000 0.000 0.000 0.000
RAW 0 37410.599 4 290361.17840 1121780.82570 9.91600 22330.60000
MSG 0 37410.538 $GPGGA,022330.60,2903.611784,N,11217.808257,E,2,08,1.0,9.916,M,0.0,M,8.0,0643*71
MSG 0 37410.581 $GPVTG,22.3,T,,M,0.08,N,0.15,K,P*23
MSG 0 37410.600 $GPZDA,022330.60,27,03,2024,00,00*62
EC1 1 37410.736 1.040
POS 0 37410.799 626291.660 3216635.561
QUA 0 37410.799 7 3.000 1.000 8.000 2.000 0.000 0.000 0.000
RAW 0 37410.799 4 290361.17890 1121780.82630 9.90800 22330.80000
MSG 0 37410.735 $GPGGA,022330.80,2903.611789,N,11217.808263,E,2,08,1.0,9.908,M,0.0,M,8.0,0643*7A
MSG 0 37410.778 $GPVTG,42.9,T,,M,0.15,N,0.27,K,P*22
MSG 0 37410.797 $GPZDA,022330.80,27,03,2024,00,00*6C
EC1 1 37410.939 1.040
POS 0 37411.000 626291.673 3216635.574
QUA 0 37411.000 7 3.000 1.000 8.000 2.000 0.000 0.000 0.000
RAW 0 37411.000 4 290361.17960 1121780.82710 9.89800 22331.00000
MSG 0 37410.938 $GPGGA,022331.00,2903.611796,N,11217.808271,E,2,08,1.0,9.898,M,0.0,M,8.0,0643*76
MSG 0 37410.981 $GPVTG,46.0,T,,M,0.17,N,0.31,K,P*2A
MSG 0 37411.001 $GPZDA,022331.00,27,03,2024,00,00*65
FIX 99 37411.109 48 626291.673 3216635.574
EC1 1 37411.138 1.030
POS 0 37411.200 626291.687 3216635.584
QUA 0 37411.200 7 3.000 1.000 8.000 2.000 0.000 0.000 0.000
RAW 0 37411.200 4 290361.18010 1121780.82800 9.90800 22331.20000
MSG 0 37411.137 $GPGGA,022331.20,2903.611801,N,11217.808280,E,2,08,1.0,9.908,M,0.0,M,4.0,0643*7F
MSG 0 37411.180 $GPVTG,54.9,T,,M,0.21,N,0.39,K,P*2D
MSG 0 37411.199 $GPZDA,022331.20,27,03,2024,00,00*67
EC1 1 37411.337 1.020
POS 0 37411.400 626291.708 3216635.595
QUA 0 37411.400 7 3.000 1.000 8.000 2.000 0.000 0.000 0.000
RAW 0 37411.400 4 290361.18070 1121780.82930 9.90400 22331.40000
MSG 0 37411.336 $GPGGA,022331.40,2903.611807,N,11217.808293,E,2,08,1.0,9.904,M,0.0,M,4.0,0643*71
MSG 0 37411.379 $GPVTG,57.9,T,,M,0.23,N,0.42,K,P*20
MSG 0 37411.398 $GPZDA,022331.40,27,03,2024,00,00*61
EC1 1 37411.538 1.030
POS 0 37411.599 626291.727 3216635.606
QUA 0 37411.599 7 3.000 1.000 8.000 2.000 0.000 0.000 0.000
RAW 0 37411.599 4 290361.18130 1121780.83050 9.90100 22331.60000
MSG 0 37411.537 $GPGGA,022331.60,2903.611813,N,11217.808305,E,2,08,1.0,9.901,M,0.0,M,4.0,0643*7D
MSG 0 37411.580 $GPVTG,61.7,T,,M,0.22,N,0.41,K,P*29
MSG 0 37411.600 $GPZDA,022331.60,27,03,2024,00,00*63
EC1 1 37411.737 1.020
POS 0 37411.799 626291.750 3216635.618
QUA 0 37411.799 7 3.000 1.000 8.000 2.000 0.000 0.000 0.000
RAW 0 37411.799 4 290361.18190 1121780.83190 9.89600 22331.80000
MSG 0 37411.736 $GPGGA,022331.80,2903.611819,N,11217.808319,E,2,08,1.0,9.896,M,0.0,M,4.0,0643*7B
MSG 0 37411.779 $GPVTG,64.7,T,,M,0.25,N,0.45,K,P*2F
MSG 0 37411.798 $GPZDA,022331.80,27,03,2024,00,00*6D
EC1 1 37411.937 1.030
POS 0 37412.000 626291.774 3216635.627
QUA 0 37412.000 7 3.000 1.000 8.000 2.000 0.000 0.000 0.000
RAW 0 37412.000 4 290361.18240 1121780.83340 9.89900 22332.00000
MSG 0 37411.937 $GPGGA,022332.00,2903.611824,N,11217.808334,E,2,08,1.0,9.899,M,0.0,M,4.0,0643*7E
MSG 0 37411.980 $GPVTG,68.6,T,,M,0.25,N,0.47,K,P*20
MSG 0 37411.999 $GPZDA,022332.00,27,03,2024,00,00*66
EC1 1 37412.138 1.020
POS 0 37412.200 626291.790 3216635.646

3.1、中規(guī)中矩的雙循環(huán)

以下代碼實例中,是 Hypack RAW 數(shù)據(jù)處理中的雙循環(huán),插補 EC1 采集數(shù)據(jù)所在定位坐標。
數(shù)據(jù)的時間秒從小到大有序排列。

	 for (int j = 0; j < POSLeng; j++)
	 {
	     if (j == 0 && EC1Time[i] < POSTime[j])//EC1時間小于第一個POS時間
	     {
	         EC1East[i] = POSEast[j] - (POSEast[j + 1] - POSEast[j]) / (POSTime[j + 1] - POSTime[j]) * (POSTime[j] - EC1Time[i]);//水深點東坐標
	         EC1North[i] = POSNorth[j] - (POSNorth[j + 1] - POSNorth[j]) / (POSTime[j + 1] - POSTime[j]) * (POSTime[j] - EC1Time[i]);//水深點北坐標
	         break;
	     }
	     if (j == POSLeng - 1 && EC1Time[i] > POSTime[POSLeng - 1])//EC1時間大于最后一個POS時間
	     {
	         EC1East[i] = POSEast[j] + (POSEast[j] - POSEast[j - 1]) / (POSTime[j] - POSTime[j - 1]) * (EC1Time[i] - POSTime[j]);//水深點東坐標
	         EC1North[i] = POSNorth[j] + (POSNorth[j] - POSNorth[j - 1]) / (POSTime[j] - POSTime[j - 1]) * (EC1Time[i] - POSTime[j]);//水深點北坐標
	         break;
	     }
	     if (EC1Time[i] == POSTime[j])
	     {
	         EC1East[i] = POSEast[j];
	         EC1North[i] = POSNorth[j];
	         break;
	     }
	     if ((EC1Time[i] > POSTime[j]) && (EC1Time[i] < POSTime[j + 1]))
	     {
	         EC1East[i] = POSEast[j] + (POSEast[j + 1] - POSEast[j]) / (POSTime[j + 1] - POSTime[j]) * (EC1Time[i] - POSTime[j]);//水深點東坐標
	         EC1North[i] = POSNorth[j] + (POSNorth[j + 1] - POSNorth[j]) / (POSTime[j + 1] - POSTime[j]) * (EC1Time[i] - POSTime[j]);//水深點北坐標
	         break;
	     }
	 }
	 SurveyEC1[i, 0] = EC1Time[i];
	 SurveyEC1[i, 1] = EC1East[i];
	 SurveyEC1[i, 2] = EC1North[i];
	 SurveyEC1[i, 3] = EC1WaterDepth[i];

以上代碼循環(huán)效率不高,測試中,當 RAW 文件 3119 KB,EC1 數(shù)據(jù)量達到 97981 個,POS數(shù)據(jù)量達到 6142 個,F(xiàn)IX數(shù)據(jù)量達到 503個。插補 EC1 采集點的坐標和 從 EC1 采集點檢索 FIX 采集的水深,很耗時,達到 2 千毫秒左右,插補數(shù)據(jù)后,還要加載到 chart 和 dataGridView 圖表控件中,加載圖標達到 7 百毫秒左右,導(dǎo)致顯示很慢。

3.2、采用改進二分法的雙循環(huán)

為了提高運算速度和效率,采用改進二分法的雙循環(huán),根據(jù)循環(huán)原則,優(yōu)化代碼結(jié)構(gòu),使用類封裝坐標計算循環(huán)為 InterpCoord 函數(shù),二分法循環(huán)調(diào)用它。插補 EC1 采集點的坐標和 FIX 采集的水深,整體循環(huán)減小到 764 毫秒左右。

  //根據(jù) POS 定位數(shù)據(jù)和時間數(shù)據(jù),以航速計算插補 EC1 水深的定位坐標
  //改進二分法,加快循環(huán)
  int EC1Leng = ListEc1Time.Length;//EC1數(shù)據(jù)個數(shù)
  int MedianNum = 0;
  if ((EC1Leng & 1) == 0)
  {
      MedianNum = EC1Leng / 2;//偶數(shù),數(shù)據(jù)半數(shù)
  }
  else
  {
      MedianNum = (int)(EC1Leng / 2) + 1; //奇數(shù),數(shù)據(jù)半數(shù)+1
  }

  for (int i = 0; i <= MedianNum; i++)//for (int i = 0; i < EC1Leng; i++)
  {
      //從時間秒最小索引 i = 0 開始順序計算到中數(shù)
      InterpCoord(EC1Time[i], ref EC1East[i], ref EC1North[i], POSTime, POSEast, POSNorth);
      SurveyEC1[i, 0] = EC1Time[i];
      SurveyEC1[i, 1] = EC1East[i];
      SurveyEC1[i, 2] = EC1North[i];
      SurveyEC1[i, 3] = EC1WaterDepth[i];

      //從時間秒最大索引 i = EC1Leng - 1 開始逆序計算到中數(shù)
      int ReverseOrderNum = EC1Leng - i - 1;
      InterpCoord(EC1Time[ReverseOrderNum], ref EC1East[ReverseOrderNum], ref EC1North[ReverseOrderNum], POSTime, POSEast, POSNorth);

      //組合為二維 EC1 數(shù)據(jù)
      SurveyEC1[ReverseOrderNum, 0] = EC1Time[ReverseOrderNum];
      SurveyEC1[ReverseOrderNum, 1] = EC1East[ReverseOrderNum];
      SurveyEC1[ReverseOrderNum, 2] = EC1North[ReverseOrderNum];
      SurveyEC1[ReverseOrderNum, 3] = EC1WaterDepth[ReverseOrderNum];
  }

使用類封裝坐標計算循環(huán)為 InterpCoord 函數(shù),以便構(gòu)造引用:

 public class Hypack
 {
        /// <summary>計算 EC1 時間點的坐標</summary>
        /// <param name="InterpTime">EC1時間點</param>
        /// <param name="InterpEast">EC1東坐標</param>
        /// <param name="InterpNorth">EC1西坐標</param>
        /// <param name="LineTime">POS時間點</param>
        /// <param name="LineEast">POS東坐標</param>
        /// <param name="LineNorth">POS西坐標</param>
       public static void InterpCoord(double InterpTime, ref double InterpEast, ref double InterpNorth, double[] LineTime, double[] LineEast, double[] LineNorth)
       {
           int LineLeng = LineTime.Length;

           if (InterpTime < LineTime[0])//EC1時間小于第一個 POS 線上時間,計算EC1時間對應(yīng)坐標
           {
               InterpEast = LineEast[0] - (LineEast[1] - LineEast[0]) / (LineTime[1] - LineTime[0]) * (LineTime[0] - InterpTime);//水深點東坐標
               InterpNorth = LineNorth[0] - (LineNorth[1] - LineNorth[0]) / (LineTime[1] - LineTime[0]) * (LineTime[0] - InterpTime);//水深點北坐標
           }
           else if (InterpTime > LineTime[LineLeng - 1])//EC1時間大于最后一個 POS 線上時間,計算EC1時間對應(yīng)坐標
           {
               InterpEast = LineEast[LineLeng - 1] + (LineEast[LineLeng - 1] - LineEast[LineLeng - 2]) / (LineTime[LineLeng - 1] - LineTime[LineLeng - 2]) * (InterpTime - LineTime[LineLeng - 1]);//水深點東坐標
               InterpNorth = LineNorth[LineLeng - 1] + (LineNorth[LineLeng - 1] - LineNorth[LineLeng - 2]) / (LineTime[LineLeng - 1] - LineTime[LineLeng - 2]) * (InterpTime - LineTime[LineLeng - 1]);//水深點北坐標
           }
           else
           {
               for (int j = 0; j < LineLeng; j++)
               {
                   if (InterpTime == LineTime[j])//EC1時間等于 POS 線上時間,坐標一致
                   {
                      InterpEast = LineEast[j];
                      InterpNorth = LineNorth[j];
                      break;
                   }
                   if ((InterpTime > LineTime[j]) && (InterpTime < LineTime[j + 1]))//EC1時間在 POS 線上 2 個時間之間,計算EC1時間對應(yīng)坐標
                   {
                      InterpEast = LineEast[j] + (LineEast[j + 1] - LineEast[j]) / (LineTime[j + 1] - LineTime[j]) * (InterpTime - LineTime[j]);//水深點東坐標
                      InterpNorth = LineNorth[j] + (LineNorth[j + 1] - LineNorth[j]) / (LineTime[j + 1] - LineTime[j]) * (InterpTime - LineTime[j]);//水深點北坐標
                      break;
                   }
               }
           }
     // 嘗試如下代碼更耗時,相當于增加了循環(huán),盡管代碼簡潔
      找到大于目標的第一個元素的索引
     //int indexGreaterThan = Array.FindIndex(LineTime, n => n > InterpTime);
      找到等于于target的第一個元素的索引
     //int indexEqualThan = Array.FindIndex(LineTime, n => n == InterpTime);
      找到小于target的第一個元素的索引
     //int indexLessThan = Array.FindLastIndex(LineTime, n => n < InterpTime);
     //if (indexEqualThan >= 0)
     //{
     //    InterpEast = LineEast[indexEqualThan];
     //    InterpNorth = LineNorth[indexEqualThan];
     //}

     //if (indexLessThan >= 0 && indexGreaterThan >= 0)
     //{
     //    InterpEast = LineEast[indexLessThan] + (LineEast[indexGreaterThan] - LineEast[indexLessThan]) / (LineTime[indexGreaterThan] - LineTime[indexLessThan]) * (InterpTime - LineTime[indexLessThan]);//水深點東坐標
     //    InterpNorth = LineNorth[indexLessThan] + (LineNorth[indexGreaterThan] - LineNorth[indexLessThan]) / (LineTime[indexGreaterThan] - LineTime[indexLessThan]) * (InterpTime - LineTime[indexLessThan]);//水深點北坐標
     //}
       }
}

3.3 、采用并行循環(huán)

為了提高到更快的運算速度和效率,采用并行循環(huán),優(yōu)化代碼結(jié)構(gòu),調(diào)用類封裝的坐標計算循環(huán)為 InterpCoord 函數(shù)。插補 EC1 采集點的坐標和 FIX 采集的水深,整體循環(huán)減小到 377 毫秒左右。

   Parallel.For(0, EC1Leng, j =>
   {
        InterpCoord(EC1Time[j], ref EC1East[j], ref EC1North[j], POSTime, POSEast, POSNorth);
        SurveyEC1[j, 0] = EC1Time[j];
        SurveyEC1[j, 1] = EC1East[j];
        SurveyEC1[j, 2] = EC1North[j];
        SurveyEC1[j, 3] = EC1WaterDepth[j];
   });

四、雙循環(huán)更好的辦法

多線程處理不當容易內(nèi)存溢出,線程間的錯誤處理和同步問題。需要嚴謹?shù)谋苊舛鄠€線程同時訪問同一資源,否則導(dǎo)致沖突或錯誤。‌存在內(nèi)存銷毀消耗,處理不當反而浪費時間,增加開銷。其它方法還在探索中…

以上就是加快C#雙循環(huán)的速度效率的方法的詳細內(nèi)容,更多關(guān)于C#雙循環(huán)速度的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論