2015-01-21 2 views
1

У меня есть это. Это приложение для создания банковских счетовThreading с записью в файловую систему

static void Main(string[] args) 
    { 

     string path = @"G:\BankNumbers"; 
     var bans = BankAcoutNumbers.BANS; 
     const int MAX_FILES = 80; 
     const int BANS_PER_FILE = 81818182/80; 
     int bansCounter = 0; 
     var part = new List<int>(); 
     var maxNumberOfFiles = 10; 
     Stopwatch timer = new Stopwatch(); 
     var fileCounter = 0; 


     if (!Directory.Exists(path)) 
     { 
      DirectoryInfo di = Directory.CreateDirectory(path); 
     } 

     try 
     { 
      while (fileCounter <= maxNumberOfFiles) 
      { 
       timer.Start(); 
       foreach (var bank in BankAcoutNumbers.BANS) 
       { 
        part.Add(bank); 
        if (++bansCounter >= BANS_PER_FILE) 
        { 
         string fileName = string.Format("{0}-{1}", part[0], part[part.Count - 1]); 
         string outputToFile = "";// Otherwise you dont see the lines in the file. Just single line!! 

         Console.WriteLine("NR{0}", fileName); 
         string subString = System.IO.Path.Combine(path, "BankNumbers");//Needed to add, because otherwise the files will not stored in the correct folder!! 
         fileName = subString + fileName; 

         foreach (var partBan in part) 
         { 

          Console.WriteLine(partBan); 
          outputToFile += partBan + Environment.NewLine;//Writing the lines to the file 

         } 
         System.IO.File.WriteAllText(fileName, outputToFile);//Writes to file system. 
         part.Clear(); 
         bansCounter = 0; 
         //System.IO.File.WriteAllText(fileName, part.ToString()); 

         if (++fileCounter >= MAX_FILES) 
          break; 
        } 
       } 
      } 

      timer.Stop(); 
      Console.WriteLine(timer.Elapsed.Seconds); 
     } 
     catch (Exception) 
     { 

      throw; 
     } 

     System.Console.WriteLine("Press any key to exit."); 
     System.Console.ReadKey(); 
    } 

Но это порождает 81 миллионов записей банковского счета разделенных более 80 файлов. Но могу ли я ускорить процесс с потоками?

+1

Вероятно, нет, нет. В любом случае, вы можете попробовать и узнать сами. Это лучший способ получить окончательный ответ. – Servy

+1

Вы пытались http://stackoverflow.com/questions/16191591/what-consumes-less-resources-and-is-faster-file-appendtext-or-file-writealltext? –

+0

Используйте «StringBuilder» вместо конкатенации строк в цикле. Или просто 'File.WriteAllLines (fileName, part)' исключает цикл. – CodesInChaos

ответ

1

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

Вы, , могут видеть небольшое увеличение скорости, если вы создаете рабочий поток, ответственный только за файлIO. Другими словами, создайте буфер, вставьте в него содержимое дампа основного потока, а другой поток записывает его на диск. Это классическая динамика производителя/потребителя. Однако я бы не ожидал серьезных успехов в скорости.

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

Edit: Также посмотрите на ссылку L-три при условии, используя BufferedStream будет улучшение (и, вероятно, оказывают потребительскую нить ненужное)

+0

Спасибо за ваш комментарий. Можете привести пример. Спасибо. Но ключевое слово Async - это не то, чтобы ускорить его? –

+0

Проблема здесь заключается в том, чтобы записать файл на диск. Вы можете использовать несколько потоков для генерации данных, которые хотите сохранить, но вы уже * собираетесь генерировать данные быстрее, чем вы можете записать их на диск. Если вы ускорите это, очередь будет просто заполняться быстрее. Мой опыт - это не C#, но я подозреваю, что это уже буферизованный вывод, что означает, что вы, вероятно, должны ожидать минимальных выигрышей от многопоточности. – TASagent

+0

@Nielsfischerein Нет, это не так. Это ключевое слово, которое упрощает запись асинхронного кода. Это все. – Servy

0

Ваш процесс можно разделить на два этапа:

  1. Сформировать счет
  2. Сохранить счет в файле

Первый шаг гр это делается параллельно, поскольку между учетными записями нет зависимости. То есть, создавая номер учетной записи xyz, вам не нужно полагаться на данные со счета xyz - 1 (так как он еще не создан).

Проблемный бит записывает данные в файл. Вы не хотите, чтобы несколько потоков пытались получить доступ и записать в один и тот же файл. И добавление блокировок, скорее всего, сделает ваш кодекс кошмаром для поддержания. Другая проблема заключается в том, что запись в файл замедляет весь процесс.

На данный момент в вашем коде создание учетной записи и запись в файл происходит в одном процессе.

Что вы можете попробовать - это разделить эти процессы. Итак, сначала вы создаете все учетные записи и храните их в какой-то коллекции. Здесь многопоточность может использоваться безопасно. Только когда все учетные записи созданы, вы их сохраняете.

Для улучшения процесса экономии потребуется больше работы. Вам придется разделить все учетные записи на 8 отдельных коллекций. Для каждой коллекции вы создаете отдельный файл. Затем вы можете взять первый коллекцию, первый файл и создать поток, который будет записывать данные в файл. То же самое для второй коллекции и второго файла. И так далее. Эти 8 процессов могут выполняться параллельно, и вам не нужно беспокоиться о том, что более одного потока попытается получить доступ к одному файлу.

Ниже какой-то псевдо-код, чтобы проиллюстрировать идею:

public void CreateAndSaveAccounts() 
    { 
     List<Account> accounts = this.CreateAccounts(); 

     // Divide the accounts into separate batches 
     // Of course the process can (and shoudl) be automated. 
     List<List<Account>> accountsInSeparateBatches = 
      new List<List<Account>> 
      { 
       accounts.GetRange(0, 10000000),    // Fist batch of 10 million 
       accounts.GetRange(10000000, 10000000),  // Second batch of 10 million 
       accounts.GetRange(20000000, 10000000)  // Third batch of 10 million 
       // ... 
      }; 

     // Save accounts in parallel 
     Parallel.For(0, accountsInSeparateBatches.Count, 
      i => 
       { 
        string filePath = string.Format(@"C:\file{0}", i); 
        this.SaveAccounts(accountsInSeparateBatches[i], filePath); 
       } 
      ); 
    } 

    public List<Account> CreateAccounts() 
    { 
     // Create accounts here 
     // and return them as a collection. 
     // Use parallel processing wherever possible 
    } 

    public void SaveAccounts(List<Account> accounts, string filePath) 
    { 
     // Save accounts to file 
     // The method creates a thread to do the work. 
    } 
Смежные вопросы