2016-07-06 2 views
2

Мне нужно прочитать данные из файла, обработать и записать результат в другой файл. Я использую BackgroundWorker, чтобы показать состояние процесса .I написать что-то вроде этого, чтобы использовать в DoWork случае BackgroundWorkerИспользование потока (задачи) для выполнения работы содержит ввод-вывод

private void ProcData(string fileToRead,string fileToWrite) 
     { 
      byte[] buffer = new byte[4 * 1024]; 

      //fileToRead & fileToWrite have same size 
      FileInfo fileInfo = new FileInfo(fileToRead); 

      using (FileStream streamReader = new FileStream(fileToRead, FileMode.Open)) 
      using (BinaryReader binaryReader = new BinaryReader(streamReader)) 
      using (FileStream streamWriter = new FileStream(fileToWrite, FileMode.Open)) 
      using (BinaryWriter binaryWriter = new BinaryWriter(streamWriter)) 
      { 
       while (streamWriter.Position < fileInfo.Length) 
       { 
        if (streamWriter.Position + buffer.Length > fileInfo.Length) 
        { 
         buffer = new byte[fileInfo.Length - streamWriter.Position]; 
        } 

        //read 
        buffer = binaryReader.ReadBytes(buffer.Length); 

        //proccess 
        Proc(buffer); 

        //write 
        binaryWriter.Write(buffer); 

        //report if procentage changed 
        //... 

       }//while 
      }//using 
     } 

, но это более 5 раз медленнее, чем просто чтение из fileToRead и записи fileToWrite так что я думаю о резьбе. Я читал некоторые вопросы на сайте и попробовать что-то вроде этой базы на this question

private void ProcData2(string fileToRead, string fileToWrite) 
     { 
      int threadNumber = 4; //for example 

      Task[] tasks = new Task[threadNumber]; 

      long[] startByte = new long[threadNumber]; 
      long[] length = new long[threadNumber]; 

      //divide file to threadNumber(4) part 
      //and update startByte & length 

      var parentTask = Task.Run(() => 
      { 
       for (int i = 0; i < threadNumber; i++) 
       { 
        tasks[i] = Task.Factory.StartNew(() => 
        { 
         Proc2(fileToRead, fileToWrite, startByte[i], length[i]); 
        }); 
       } 
      }); 

      parentTask.Wait(); 

      Task.WaitAll(tasks); 

     } 
     // 
     private void Proc2(string fileToRead,string fileToWrite,long fileStartByte,long partLength) 
     { 
      byte[] buffer = new byte[4 * 1024]; 

      using (FileStream streamReader = new FileStream(fileToRead, FileMode.Open,FileAccess.Read,FileShare.Read)) 
      using (BinaryReader binaryReader = new BinaryReader(streamReader)) 
      using (FileStream streamWriter = new FileStream(fileToWrite, FileMode.Open,FileAccess.Write,FileShare.Write)) 
      using (BinaryWriter binaryWriter = new BinaryWriter(streamWriter)) 
      { 
       streamReader.Seek(fileStartByte, SeekOrigin.Begin); 
       streamWriter.Seek(fileStartByte, SeekOrigin.Begin); 

       while (streamWriter.Position < fileStartByte+partLength) 
       { 
        if (streamWriter.Position + buffer.Length > fileStartByte+partLength) 
        { 
         buffer = new byte[fileStartByte+partLength - streamWriter.Position]; 
        } 

        //read 
        buffer = binaryReader.ReadBytes(buffer.Length); 

        //proccess 
        Proc(buffer); 

        //write 
        binaryWriter.Write(buffer); 

        //report if procentage changed 
        //... 

       }//while 
      }//using 
     } 

, но я думаю, что есть какая-то проблема и каждое переключение времени задачи ему нужно снова искать. Я думаю о чтении файла, используйте threading для Proc(), а затем записываю результат, но он кажется неправильным. Как я могу сделать это правильно? (Чтение буфера из файла, обработка и запись его в другом файле с помощью задачи)

// ================== ======================================

Основание на посту Пита Киркхэма Я изменил свой метод. Я не знаю почему, но это не сработало для меня. Я добавил новый метод, который может помочь им. спасибо каждое тело

private void ProcData3(string fileToRead, string fileToWrite) 
     { 
      int bufferSize = 4 * 1024; 
      int threadNumber = 4;//example 
      List<byte[]> bufferPool = new List<byte[]>(); 
      Task[] tasks = new Task[threadNumber]; 

      //fileToRead & fileToWrite have same size 
      FileInfo fileInfo = new FileInfo(fileToRead); 

      using (FileStream streamReader = new FileStream(fileToRead, FileMode.Open)) 
      using (BinaryReader binaryReader = new BinaryReader(streamReader)) 
      using (FileStream streamWriter = new FileStream(fileToWrite, FileMode.Open)) 
      using (BinaryWriter binaryWriter = new BinaryWriter(streamWriter)) 
      { 
       while (streamWriter.Position < fileInfo.Length) 
       { 
        //read 
        for (int g = 0; g < threadNumber; g++) 
        { 
         if (streamWriter.Position + bufferSize <= fileInfo.Length) 
         { 
          bufferPool.Add(binaryReader.ReadBytes(bufferSize)); 
         } 
         else 
         { 
          bufferPool.Add(binaryReader.ReadBytes((int)(fileInfo.Length - streamWriter.Position))); 
          break; 
         } 
        } 

        //do 
        var parentTask = Task.Run(() => 
        { 
         for (int th = 0; th < bufferPool.Count; th++) 
         { 
          int index = th; 

          //threads 
          tasks[index] = Task.Factory.StartNew(() => 
          { 
           Proc(bufferPool[index]); 
          }); 

         }//for th 
        }); 

        //stop parent task(run childs) 
        parentTask.Wait(); 

        //wait till all task be done 
        Task.WaitAll(tasks); 

        //write 
        for (int g = 0; g < bufferPool.Count; g++) 
        { 
         binaryWriter.Write(bufferPool[g]); 
        } 

        //report if procentage changed 
        //... 

       }//while 
      }//using 
     } 
+0

Глядя на это, можно сказать, что самая медленная часть вашего процесса была на самом деле IO, поэтому разбивая ее на 4, а затем обрабатывая ее, вы просто заканчиваете задержку процесса на IO. – BugFinder

+0

Это, вероятно, медленнее, потому что ваш буфер и рабочий размер слишком малы, что приводит к большему количеству операций ввода-вывода. Есть сладкое пятно, где размер буфера не должен быть слишком маленьким или слишком большим. – MickyD

+0

Почему вы выделяете «буфер»? 'BinaryReader.ReadBytes()' _ возвращает ваш буфер, нет необходимости выделять его самостоятельно. И если IO - причина, по которой это происходит медленно, создание большего количества потоков не поможет, поскольку у вас есть только один диск. –

ответ

1

По сути вы хотите разделить обработку данных вверх в параллельные задачи, но вы не хотите, хотите разделить IO вверх.

Как это происходит, зависит от размера ваших данных. Если он достаточно мал, чтобы вписаться в память, вы можете прочитать все это в массив ввода и создать выходной массив, а затем создать задачи для обработки некоторого входного массива и заполнить часть выходного массива, а затем записать весь выходной массив в файл.

Если данные для этого слишком велики, вам необходимо ограничить количество прочитанных и записанных данных одновременно. Таким образом, у вас есть основной поток, который начинается с чтения N блоков данных и создания N задач для их обработки. Затем вы ждете завершения задач в порядке, и каждый раз, когда вы завершаете, вы записываете блок вывода и читаете новый блок ввода и создаете другую задачу. Некоторые эксперименты потребуются для хорошего значения для N и размера блока, что означает, что задачи, как правило, заканчиваются примерно с той же скоростью, с которой работает IO.

+0

спасибо, потому что ваш пост не содержал никакого кода. Я обновил свой пост. это не сработало для меня, но это кажется правдой. танки – NokhodSiah