2014-12-04 82 views
-2

我正在编写一个程序,它应该替换或删除logfile.txt中的一些条目。 代码工作正常(至少对于小型LogFiles)。如果我使用大文件(例如27 MB),它会变得非常缓慢并且UI冻结。我不能点击任何东西。UI冻结和计算真的很慢

在按钮点击我执行此方法:

 private string delete_Lines(string[] lines, string searchString) 
    { 

     for (int i = 0; i < lines.Length; i++) 
     { 

      if (lines[i].Contains(searchString)) 
      { 
       rtbLog.Text += "Deleting(row " + (i + 1) + "):\n" + lines[i] + "\n"; 
       progressBar1.Value += 1; 
       if (cbDB == true) 
       { 
        while (is_next_line_block(lines, i) == true) 
        { 
         i++; 
         rtbLog.Text += lines[i] + "\n"; 
         progressBar1.Value += 1; 
        } 
       } 

      } 
      else 
      { 
       res += lines[i]+"\n"; 
       progressBar1.Value += 1; 
      } 

     } 
     tssLbl.Text = "Done!"; 
     rtbLog.Text += "...Deleting finished\n"; 
     return res; 
    } 

行是日志文件我试图清理的阵列。每个条目都是单行。 tssLbl是一个通知标签,rtbLog是一个richTextBox,我跟踪哪一行正在删除。

is_next_line_block是另一种方法,它是检查下一行是我想要删除的块的一部分。这种方法的参数是整行数组和行位置。

private bool is_next_line_block(string[] lines, int curIndex) 
    { 
     if (curIndex < lines.Length-1) 
     { 
      if (lines[curIndex + 1].StartsWith(" ")) 
      { 
       return true; 
      } 
      else 
      { 
       return false; 
      } 
     } 
     else 
     { 
      return false; 
     } 

    } 

有没有人有任何想法,是什么导致冻结,并在减慢程序?我知道,我可以通过并行化来加速我的代码,但我无法想象,检查没有并行性的27 MB txt文件需要很长时间。

+0

'BackgroundWorker' _does_使用线程,它专门设计用于允许进度更新到用户界面。如果你无法解决这个问题,请专门提出一个问题。至于性能,使用其他线程模型不会改变性能。如果处理27MB需要很长时间,那么该文件是最慢的磁盘,或者处理速度太慢。无论如何,你需要将这个例子缩小到更简单一些,一次只关注一个问题。请参阅http://stackoverflow.com/help/mcve和http://stackoverflow.com/help/how-to-ask – 2014-12-04 04:02:09

+0

认真考虑将代码移到单独的类中,并且对该类的调用需要相应的参数你现在怎么做。现在将这个类实例化并通过Task.Factory调用它。开始()'并告诉我它是否仍在放慢你的应用程序。如果您需要设置/取消设置视觉线索(例如进度条等),请记得添加一个'.ContinueWith'。 – code4life 2014-12-04 04:07:21

+0

@PeterDuniho我编辑我的问题和代码块,所以它可以更好地阅读。 ty的建议。 at code4life:可以肯定的是,我的理解正确: 您希望我将整个代码(期望从ui中获得的部分)移动到一个新类中并在那里进行计算?说实话,我不知道你的意思是什么Task.Factory.Start()和究竟是什么.ContinueWith? – Depa 2014-12-04 04:19:44

回答

0

您在这里有几个问题:

  1. 您正在阅读缓冲整个文件(字符串数组),我猜你在呼唤File.ReadAllLines()。在缓冲区中读取大文件会减慢你的速度,并且在极端的情况下会让你失去内存。

  2. 您正在为富文本框Text属性使用+ =操作。这是非常耗时的操作,因为每次以这种方式更新文本属性时,UI必须呈现整个富文本框。更好的选择是使用字符串生成器来加载这些文本,并定期更新富文本框。

要解决此问题,您需要将文件读取为流。可以根据读取的字节而不是行位置来监视进度。您可以运行读取操作异步并监视计时器的进度,如下例所示。

private void RunFileOperation(string inputFile, string search) 
{ 
    Timer t = new Timer(); 
    int progress = 0; 
    StringBuilder sb = new StringBuilder(); 

    // Filesize serves as max value to check progress 
    progressBar1.Maximum = (int)(new FileInfo(inputFile).Length); 
    t.Tick += (s, e) => 
     { 
      rtbLog.Text = sb.ToString(); 
      progressBar1.Value = progress; 
      if (progress == progressBar1.Maximum) 
      { 
       t.Enabled = false; 
       tssLbl.Text = "done"; 
      } 
     }; 
    //update every 0.5 second  
    t.Interval = 500; 
    t.Enabled = true; 
    // Start async file read operation 
    System.Threading.Tasks.Task.Factory.StartNew(() => delete_Lines(inputFile, search, ref progress, ref sb));  
} 

private void delete_Lines(string fileName, string searchString, ref int progress, ref StringBuilder sb) 
{ 
    using (var file = File.OpenText(fileName)) 
    { 
     int i = 0; 
     while (!file.EndOfStream) 
     { 
      var line = file.ReadLine(); 
      progress = (int)file.BaseStream.Position; 
      if (line.Contains(searchString)) 
      { 
       sb.AppendFormat("Deleting(row {0}):\n{1}", (i + 1), line); 
       // Change this algorithm for nextline check 
       // Do this when it is next line, i.e. in this line. 
       // "If" check above can check if (line.startswith(" "))... 
       // instead of having to do it nextline next here. 
       /*if (cbDB == true) 
       { 
        while (is_next_line_block(lines, i) == true) 
        { 
         i++; 
         rtbLog.Text += lines[i] + "\n"; 
         progressBar1.Value += 1; 
        } 
       }*/ 
      } 
     } 
    }   
    sb.AppendLine("...Deleting finished\n"); 
} 
+0

像魅力一样工作。 tylyly。需要做一些调整,但我猜测主要工作已经完成。当我完成后,我会发布工作代码,以防万一有人对此问题的工作结果感兴趣。 – Depa 2014-12-04 19:42:36

0

作为后续行动上Task.Factory.Start()使用你的问题,它的完成这种方式(一般):

// you might need to wrap this in a Dispatcher.BeginInvoke (see below) 
// if you are not calling from the main UI thread 
CallSomeMethodToSetVisualCuesIfYouHaveOne(); 

Task.Factory.StartNew(() => 
{ 
    // code in this block will run in a background thread... 
} 
.ContinueWith(task => 
{ 
    // if you called the task from the UI thread, you're probably 
    // ok if you decide not to wrap the optional method call below 
    // in a dispatcher begininvoke... 
    Application.Current.Dispatcher.BeginInvoke(new Action(()=> 
    { 
     CallSomeMethodToUnsetYourVisualCuesIfYouHaveAnyLOL(); 
    })); 
} 

希望这有助于!

+0

ty的解释。已经修好了,但不好记住。 – Depa 2014-12-04 19:43:55

0

感谢大家的帮助,尤其是loopedcode,这就是工作版本(拿了loopedcode的代码,并提出了一些修改):

 private void RunFileOperation(string inputFile, string search) 
    { 
     Timer t = new Timer(); 
     StringBuilder sb = new StringBuilder(); 
     { 
      rtbLog.Text = "Start Deleting...\n"; 
     } 


     // Filesize serves as max value to check progress 
     progressBar1.Maximum = (int)(new FileInfo(inputFile).Length); 
     t.Tick += (s, e) => 
     { 
      rtbLog.Text += sb.ToString(); 
      progressBar1.Value = progress; 
      if (progress == progressBar1.Maximum) 
      { 
       t.Enabled = false; 
       tssLbl.Text = "done"; 
      } 
     }; 
     //update every 0.5 second  
     t.Interval = 500; 
     t.Enabled = true; 
     // Start async file read operation 
     if (rbtnDelete.Checked) 
     { 
      if (cbDelete.Checked) 
      { 
       System.Threading.Tasks.Task.Factory.StartNew(() => delete_Lines(inputFile, search, ref progress, ref sb, ref res1)); 
      } 
    } 
    else 
    { 
     //..do something 
    } 

    private void delete_Lines(string fileName, string searchString, ref int progress, ref  StringBuilder sb, ref StringBuilder res1) 
    { 
    bool checkNextLine=false; 
     using (var file = File.OpenText(fileName)) 
     { 
      int i = 0; 
      while (!file.EndOfStream) 
      { 
       i++; 
       var line = file.ReadLine(); 
       progress = (int)file.BaseStream.Position; 
       if (line.Contains(searchString)) 
       { 
        sb.AppendFormat("Deleting(row {0}):\n{1}\n", (i), line); 
        checkNextLine = true; 
       } 
       else 
       { 
        if (cbDB && checkNextLine && line.StartsWith(" ")) 
        { 
         sb.AppendFormat("{0}\n", line); 
        } 
        else 
        { 
         checkNextLine = false; 
         res1.AppendLine(line); 

        } 
       } 

      } 
     } 
     sb.AppendLine("\n...Deleting finished!); 
    }