2015-01-07 5 views
0

У меня есть приложение с кнопкой запуска, которая вызывает функцию продолжительного времени работы. В порядке , чтобы добавить кнопку Stop. Я добавил поток для этой функции, чтобы избежать зависания пользовательского интерфейса и иметь возможность остановить обработку в любое время.Усиление производительности для потоковой передачи

Код без нарезки в среднем занимает 12 минут, чтобы завершить обработку, но с резьбой в пути у меня ниже занимает в 4 раза больше. Ниже показан код кнопки запуска, где называется функция «LongRunningFunction». Функция нуждается в строчном аргументе для работы «LongRunningFunction (Somestring)».

Я проверил с Task.Run и Task.Factory.StartNew, но это происходит с обоими методами.

Есть ли альтернативный способ установить поток для моего случая, который не влияет на слишком большую производительность?

public partial class Form1 : Form 
{ 
    CancellationTokenSource cts = new CancellationTokenSource(); // Create the token source. 
    public Form1() 
    { 
     InitializeComponent(); 
    } 
    private void Start_Click(object sender, EventArgs e) 
    { 
     if (cts != null) 
     { 
      cts.Cancel(); 
     } 
     cts = new CancellationTokenSource(); 
     Task.Run(()=> LongRunningFunction(Somestring, cts.Token), cts.Token);    
     //Task.Factory.StartNew(() => LongRunningFunction(Somestring, cts.Token), cts.Token, TaskCreationOptions.None, TaskScheduler.Default); 
    } 
    private void Stop_Click(object sender, EventArgs e) 
    { 
     if (cts != null) 
     { 
      cts.Cancel(); 
      cts = null; 
      MessageBox.Show("Processing cancelled"); 
     } 
    } 
    public void LongRunningFunction(string String, CancellationToken token) 
    { 
     //Long running processing 
     //... 
     MessageBox.Show("Processing finished"); 
    } 
} 

Update: Единственное, что я изменил путь я объявляю функции и добавил, если заявление внутри цикла в то время как , который находится внутри функции. Как показано ниже:

  • Отмена CancelToken была добавлена ​​для того, чтобы остановить обработку при нажатии кнопки Stop.

без резьбы Объявляю функцию следующим образом:

public void LongRunningFunction(string String) 
{ 
    while (condition) 
    { 
     //My code within While loop 
    } 
    MessageBox.Show("Processing finished"); 
} 

и Thread я определить функцию так:

public void LongRunningFunction(string String, CancellationToken token) 
{ 
    while (condition) 
    { 
     if (token.IsCancellationRequested) 
     { 
      break; 
     }  
     //My code within While loop 
    } 
    if (!token.IsCancellationRequested) 
    { 
     MessageBox.Show("Processing finished"); 
    }  
} 

UPDATE2: Внутри LongRunningFunction() называется другая функция, которая печатает строки. Как показано ниже.

public void LongRunningFunction(string fileName, CancellationToken token) 
    { 
     StreamWriter writer = new StreamWriter(@outputfile, true, Encoding.UTF8, 4096); 

     using (BinaryReader reader = new BinaryReader(File.Open(fileName, FileMode.Open))) 
     { 
      List<byte> buffer = new List<byte>(); 
      List<string> buffer1 = new List<string>(); 

      SoapHexBinary hex = new SoapHexBinary(); 

      while (chunk.Length > 0) 
      { 
       if (token.IsCancellationRequested) // ### For Cancel Thread ### 
       { 
        break; 
       } // ### For Cancel Thread ###  

        chunk = reader.ReadBytes(1024); 

        foreach (byte data in chunk) 
        { 
         if (somecondition) 
         { 
          buffer.Add(data);       
         } 
         else if (other condition) 
         { 
          buffer.Add(data); 
          PrintFunction(buffer, hex, outputfile, writer); // Print Line 
         } 
         else if (some other condition) 
         { 
          buffer.Add(data); 
         } 
        }     
      }   
      if (!token.IsCancellationRequested) 
      { 
       MessageBox.Show("Processing finished"); 
      } 

     } 

     if (writer != null) 
     { 
      writer.Dispose(); 
      writer.Close(); 
     } 
    }  
    private void PrintFunction(List<byte> buffer, SoapHexBinary hex, string outputfile, StreamWriter writer) 
    { 
      if (buffer.Count > 0) 
      { 
       if (buffer.Count >= lowlimit) 
       { 
        hex.Value = buffer.ToArray(); 
        string Register = hex.ToString(); 

        Regex pattern1 = new Regex(@"some pattern"); 

        if (pattern1.IsMatch(Register)) 
        { 
         Match l1 = Regex.Match(Register, @"somepattern", RegexOptions.IgnoreCase | RegexOptions.Compiled); 
         writer.Write("{0}|{1}|{2}", Convert.ToInt32(l1.Groups[1].ToString(), 16), l1.Groups[2].Value, l1.Groups[3].Value); 
         Match l2 = Regex.Match(Register, @"otherpattern", RegexOptions.IgnoreCase | RegexOptions.Compiled); 
         if (l2.Success) 
         { 
          foreach (Match m in Regex.Matches(l2.Groups[2].ToString(), pattern2, RegexOptions.IgnoreCase | RegexOptions.Compiled)) 
          { 
           //Some foreach code 
          } 
          foreach (Match x in Regex.Matches(var, @"pattern")) 
          { 
           //come code 
          } 
          writer.WriteLine("," + String.Join(",", var1)); 
         } 
         else 
         { 
          writer.WriteLine(); 
         } 
        } 
       } 
      } 
      buffer.Clear(); 
    } 

Update3: Привет bebosh,

Я до сих пор есть сомнения, как применить в моей функции, способ определения делегата в вашем примере функции.

Моя функция выглядит следующим образом:

public void LongRunningFunction(string fileName) 
{ 
    using (BinaryReader reader = new BinaryReader(File.Open(fileName, FileMode.Open))) 
    { 
     // some code 
    } 
}  

Это может быть что-то подобное или как ?:

private void LongRunningFunction(string fileName) 
{ 
    MethodInvoker action = delegate 
    { 
     using (BinaryReader reader = new BinaryReader(File.Open(fileName, FileMode.Open))) 
     { 
      // some code 
     } 
    }; 
} 
+2

Выполнение кода в дополнительной ветке вместо потока пользовательского интерфейса не должно уменьшать производительность в четыре раза (и не должно увеличивать производительность, так как выполняется точно такая же работа, обрабатывать или обрабатывать несколько оконных сообщений). Что еще вы изменили? Что вы делаете с «CancellationToken», чего не было в исходном коде? – CodeCaster

+0

Вы должны использовать 'TaskCreationOptions.LongRunning', если операция занимает 12 минут, а не то, что приведет к замедление 4x, которое вы видите. – Servy

+0

Ваш LongRunningFunction() обновляет пользовательский интерфейс, если это возможно (с помощью диспетчера или любого другого механизма) ?. Если нет, я не вижу, как это повлияет на производительность вообще. – kha

ответ

1

Не могли бы вы попробовать этот код :

bool Stop = false; 
    Thread thread; 

    private void StartButton_Click(object sender, EventArgs e) 
    { 
     string FileName = @"...\a.bin"; 
     thread = new Thread(new ThreadStart(() => DoLongProcess(FileName))); 
     thread.IsBackground = true; 
     thread.Start(); 
    } 

    private void StopButton_Click(object sender, EventArgs e) 
    { 
     Stop = true; 
    } 


    private void DoLongProcess(string file) 
    { 
     using (BinaryReader reader = new BinaryReader(File.Open(file, FileMode.Open))) 
     { 
      int pos = 0; 
      int length = (int)reader.BaseStream.Length; 
      while (pos < length) 
      { 
       if (Stop) 
        thread.Abort(); 
       // using Invoke if you want cross UI objects 
       this.Invoke((MethodInvoker)delegate 
       { 
        label1.Text = pos.ToString(); 
       }); 
       pos += sizeof(int); 
      } 
     } 
    } 
+0

Hi bebosh. Я добавил TestButton и использовал ваш код, но как добавить структуру вашего примера для запуска моей функции с помощью аргумента строки и иметь возможность использовать кнопку остановки для отмены в любой момент? – Sarmeu

+0

Спасибо bebosh, см. Мое обновление3 в оригинальной записи. У меня все еще есть сомнения в том, как применить ваш пример в моей функции. – Sarmeu

+0

Привет, bebosh, проблема в функции требует строкового аргумента, который нужно вызвать. Определяется как «private void DoLongProcess (строковый файл) {..}». Затем в StartButton_Click() следует называть что-то вроде этого «thread = new Thread (новый ThreadStart (DoLongProcess (filename))); Но я получаю ошибку, когда делаю это в вашем коде. – Sarmeu

-1

использование прерывая нить

 Thread thread; 

     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private async void StartButtonClick(object sender, RoutedEventArgs e) 
     { 
      thread = new Thread(ExecuteLong); 
      var task = Task.Run(() => 
       thread.Start()); 
      await task; 
     } 

     private void ExecuteLong() 
     { 
      try 
      { 
       // long task 
      } 
      catch (ThreadInterruptedException e) 
      { 
       MessageBox.Show("cancelled!"); 
       return; 
      } 
      MessageBox.Show("finished"); 
     } 

     private void CancelButtonClick(object sender, RoutedEventArgs e) 
     { 
      this.thread.Interrupt(); 
     } 
+2

'var task = Task.Run (() => thread.Start()); ждать выполнения задачи: «Этот код не имеет никакого смысла. – svick

2

Ответ Бебоша был достаточно хорош. Чтобы увеличить производительность, вы можете установить ThreadPriority «thread», установив «.Priority = ThreadPriority.AboveNormal» сразу после установки «thread.IsBackground = true;».

Смежные вопросы