2015-01-15 43 views
0

我有一個線程代碼,我想顯示待處理時間以完成處理。按鈕1調用 函數「Function1()」,該函數用於在while循環中控制1024字節的塊中讀取文件,直到文件的結尾 。在「While循環」中有一個「foreach循環」,其中稱爲「Function2()」。我開始 定時器在「while循環」的開始,並在「while循環」結束時停止它。之後,我嘗試 計算aprox等待時間,首先知道將由「while循環」處理的迭代次數。 然後我保存「第一次迭代的經過時間」(可以說T1),然後將其乘以迭代次數。計算待處理時間以完成處理線程代碼C#

這將是

PendingTime = T1*Iterations. 

那我

PendingTime = PendingTime - Ti, where Ti is the ElapsedTime of the ith iteration. 

的問題是,當我嘗試用實際的代碼,T1 *迭代multiplation給我402S,實際上 的處理需要12S。

也許一些專家可以看到我做錯了什麼。提前致謝。

的代碼看起來是這樣的:

async void button1_Click(object sender, EventArgs e) 
    { 
     //Some code 
     await Task.Run(() => Function1(inputfile, cts.Token), cts.Token); 
     //Some code 
    } 

    public void Function2() 
    { 
     //Some code 
    }  

    public void Function1(string inputfile, CancellationToken token) 
    { 
     int buffer = 1024; 
     int IterationCounter = 0; 
     decimal Iterations = 1; 
     int PendingTime = 0;    

     using (BinaryReader reader = new BinaryReader(File.Open(inputfile, FileMode.Open))) 
     { 
      FileLength = (int)reader.BaseStream.Length; 
      Iterations = (int)FileLength/buffer;        

      while (chunk.Length > 0) 
      {  
       Stopwatch sw1 = Stopwatch.StartNew(); //Start time counter    
       //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
       //some code 
       chunk = reader.ReadBytes(buffer); 

       foreach (byte data in chunk) 
       { 
        //Some code 
        Function2(); //Call to Function2 
       } 
       //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

       //Checking if it is the first iteration to save the pending time 
       //Pending time would be the elapsed time for the first iteration 
       //multiplied by the number of iterations (FileLength/1024). 
       sw1.Stop(); //Stop time counter 

       if (IterationCounter == 1) 
       { 
        PendingTime = (int)((decimal)Math.Round(sw1.Elapsed.TotalMilliseconds/1000, 4)*Iterations);      
       }     
       //Show in TexBox1 the pending time 
       TextBox1.Invoke((MethodInvoker)delegate 
       { 
        PendingTime = PendingTime - (int)Math.Round(sw1.Elapsed.TotalMilliseconds/1000, 4);     
        TextBox1.Text = PendingTime + " s"; 
       }); 
      } 
     } 
    }  

更新:

我基於彼得Duniho的例如下面的代碼測試。

它可以用任何文件(即txt文件)進行測試。我用5MB的txt文件進行了測試,執行時間爲3秒,但待處理時間在TextBox1中始終顯示爲零。我錯在哪裏?

注:我改變了這一點:

double timePerIteration = sw1.Elapsed/++IterationCounter; 

這個

double timePerIteration = sw1.ElapsedMilliseconds/1000/ ++IterationCounter; 

自從我得到的錯誤:

Operator '/' cannot be applied to operands of type 'System.TimeSpan' and 'int' (CS0019) 

代碼至今。感謝幫助。

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Drawing; 
using System.IO; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace TestTimer 
{ 
    public partial class MainForm : Form 
    { 
     CancellationTokenSource cts = new CancellationTokenSource(); 
     string filename = ""; 
     long FileLength; 
     FileInfo fInfo; 
     Stopwatch sw1 = new Stopwatch(); 

     public MainForm() 
     { 
      InitializeComponent(); 
     } 

     void BtnSelectFileClick(object sender, EventArgs e) 
     { 

      OpenFileDialog ofd = new OpenFileDialog(); 
      ofd.Title = "Select file"; 
      DialogResult dr = ofd.ShowDialog(); 

      if (dr == DialogResult.OK) 
      { 
       filename = ofd.FileName; 
       fInfo = new FileInfo(filename); 
      } 
      else 
      { 
       MessageBox.Show("File not found"); 
       return; 
      }   
     } 

     async void BtnRunProcessClick(object sender, System.EventArgs e) 
     { 

      cts = new CancellationTokenSource();    
      await Task.Run(() => Function1(filename, cts.Token), cts.Token);  
     } 

    public void Function1(string inputfile, CancellationToken token) 
    { 
     int buffer = 1024; 
     int IterationCounter = 0; 
     int Iterations = 0; 
     double pendingTime = 0;    

     using (BinaryReader reader = new BinaryReader(File.Open(inputfile, FileMode.Open))) 
     { 
      FileLength = (int)reader.BaseStream.Length; 
      Iterations = (int)FileLength/buffer;       
      byte[] chunk;   

      sw1 = Stopwatch.StartNew(); //Start time counter 

      while (true) 
      {        
       chunk = reader.ReadBytes(buffer); 

       if (chunk.Length == 0) {break;} 

       foreach (byte data in chunk) 
       { 
        Thread.Sleep(90/100); 
       } 

       // pendingTime is the current average time-per-iteration, 
       // times the number of iterations left 
       double timePerIteration = sw1.ElapsedMilliseconds/1000/ ++IterationCounter; 
       pendingTime = timePerIteration * (Iterations - IterationCounter); 

       TextBox1.Invoke((MethodInvoker)delegate 
       { 
        // Let string.Format() take care of rounding for you 
        TextBox1.Text = string.Format("{0:0} s", pendingTime/1000); 
       }); 
      } 
      MessageBox.Show("Execution time: " + string.Format("{0:0} s", sw1.ElapsedMilliseconds/1000)); 
     } 
    }    

    } 
} 
+2

沒有什麼能夠保證每次迭代都會花費相同的時間,所以我建議你根據「到目前爲止所花費的時間/到目前爲止的迭代次數」對它進行平均,然後用它來計算剩餘的估計時間。 – Chris

+0

感謝克里斯的建議。我會盡力做到這一點。事情是,這將是一個固定值編碼,如果我嘗試在一臺速度較慢或速度較快的計算機上,時間會有所不同。 – Sarmeu

+0

它不會被修復,它將基於迄今爲止的手術時間。 – Chris

回答

1

我不明白你發佈的代碼是如何實際編譯的,沒關係工作。 FileLength變量似乎沒有聲明,並且您永遠不會增加變量IterationCounter,每次迭代都會給您一個負值PendingTime值。即使您增加了計數器,您的PendingTime變量的實際含義也會從計數器爲1時執行的塊變化,稍後您將從當前PendingTime變量中減去您的已用時間。

這表明您發佈的代碼並非真的是您使用的代碼,因爲顯示的剩餘時間總是爲負數(即使假設FileLength的聲明由於某種原因而意外丟失)。爲了爭論起見,我會添加一個聲明來做增量…

正如評論者Chris所說,當每次迭代的實際持續時間可能會有所不同時,因爲它似乎就是這種情況,所以最好的做法是平均所有的迭代到當前的迭代。即使這可能導致錯誤的剩餘時間顯示,並且從迭代到迭代(尤其是如果迭代次數很少)時有相當大的變化,但是至少它更可能接近。

像這樣的事情可能會爲你更好地工作:

public void Function1(string inputfile, CancellationToken token) 
{ 
    int buffer = 1024; 
    int IterationCounter = 0; 
    int Iterations; 

    using (BinaryReader reader = new BinaryReader(File.Open(inputfile, FileMode.Open))) 
    { 
     if (reader.BaseStream.Length == 0) 
     { 
      // nothing to do 
      return; 
     } 

     // NOTE: this won't work for files with length > int.MaxValue! 
     // Your original code has the same limitation, and I have not 
     // bothered to change that. 

     // Now that we know for sure the length is > 0, we can 
     // do the following to ensure a correct iteration count 
     Iterations = ((int)reader.BaseStream.Length - 1)/buffer + 1; 

     Stopwatch sw1 = Stopwatch.StartNew(); 

     while (chunk.Length > 0) 
     {  
      //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
      //some code 
      chunk = reader.ReadBytes(buffer); 

      foreach (byte data in chunk) 
      { 
       //Some code 
       Function2(); //Call to Function2 
      } 
      //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

      // pendingTime is the current average time-per-iteration, 
      // times the number of iterations left 
      double timePerIteration = sw1.ElapsedMilliseconds/++IterationCounter, 
       pendingTime = timePerIteration * 
        (Iterations - IterationCounter); 

      //Show in TexBox1 the pending time 
      TextBox1.Invoke((MethodInvoker)delegate 
      { 
       // Let string.Format() take care of rounding for you 
       TextBox1.Text = string.Format("{0:0} s", pendingTime/1000); 
      }); 
     } 
    } 
} 

除非你保證你的輸入文件總是精確的長度爲1024個字節的倍數,你也有一個錯誤在你的計算總迭代次數。我也在上面解決了這個問題。

+0

嗨,彼得。請你可以看到我對原文的更新。我測試了你的代碼,但它沒有正確顯示我的待處理時間。再次感謝。 – Sarmeu

+0

抱歉,錯字。之所以在編譯之後沒有起作用,是因爲它引入了額外的「/ 1000」,並且由於您的操作從未花費超過1000秒,所顯示的值始終爲0.我編輯過我的代碼,以顯示修復編譯器錯誤的正確方法(即只需使用'ElapsedMilliseconds'而不是'Elapsed' ...不需要其他更改)。請注意,ms設置文本時將ms轉換爲秒,因此在實際計算中不需要ms。 –

+0

嗨,彼得。它發生與您所建議的修改相同。我不確定會發生什麼。我看到你的邏輯是正確的。如果你測試我的代碼,我把任何文件放在Update裏大約10MB,你會看到總體時間顯示正確,但是在TexBox1中總是出現0. – Sarmeu