Как читать и записывать более 25000 записей / строк в текстовый файл одновременно? - PullRequest
0 голосов
/ 14 февраля 2019

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

string filePath = @"D:\Aggregate_Minute_AAPL.txt";
var records = (from line in File.ReadLines(filePath).AsParallel()                    
               select line);
    List<string> str = records.ToList();
    str.ForEach(x =>
    {
         string result = x;
         result = result.TrimStart('[').TrimEnd(']');
         var jsonString = Newtonsoft.Json.JsonConvert.DeserializeObject<List<LiveAMData>>(x);
         foreach (var item in jsonString)
         {
             string value = "";
             string dirPath = @"D:\COMB1\MinuteAggregates";
             string[] fileNames = null;
             fileNames = System.IO.Directory.GetFiles(dirPath, item.sym+"_*.txt", System.IO.SearchOption.AllDirectories);
             if(fileNames.Length > 0)
             {
                 string _fileName = fileNames[0];
                 var lineList = System.IO.File.ReadAllLines(_fileName).ToList();
                 lineList.RemoveAt(0);
                 var _item = lineList[lineList.Count - 1];
                 if (!_item.Contains(item.sym))
                 {
                      lineList.RemoveAt(lineList.Count - 1);
                 }
                 System.IO.File.WriteAllLines((_fileName), lineList.ToArray());
                 value = $"{item.sym},{item.s},{item.o},{item.h},{item.c},{item.l},{item.v}{Environment.NewLine}";
                 using (System.IO.StreamWriter sw = System.IO.File.AppendText(_fileName))
                 {
                      sw.Write(value);
                 }
              }
          }
 });

Как ускорить процесс, если приложение выполняет это, тогда это занимает от 3000 до 4000 символов.и если нет никакого процесса, то он выполняет 25000 строк в минуту.Так как же увеличить время выполнения строки / процесс со всем этим кодом?

1 Ответ

0 голосов
/ 14 февраля 2019

Сначала вам нужно очистить свой код, чтобы получить больше видимости, я сделал быстрый рефакторинг, и вот что я получил

const string FilePath = @"D:\Aggregate_Minute_AAPL.txt";

class SomeClass
{
    public string Sym { get; set; }
    public string Other { get; set; }
}

private void Something() {
    File
        .ReadLines(FilePath)
        .AsParallel()
        .Select(x => x.TrimStart('[').TrimEnd(']'))
        .Select(JsonConvert.DeserializeObject<List<SomeClass>>)
        .ForAll(WriteRecord);
}

private const string DirPath = @"D:\COMB1\MinuteAggregates";
private const string Separator = @",";

private void WriteRecord(List<SomeClass> data)
{
    foreach (var item in data)
    {
        var fileNames = Directory
            .GetFiles(DirPath, item.Sym+"_*.txt", SearchOption.AllDirectories);
        foreach (var fileName in fileNames)
        {
            var fileLines = File.ReadAllLines(fileName)
                .Skip(1).ToList();
            var lastLine = fileLines.Last();
            if (!lastLine.Contains(item.Sym))
            {
                fileLines.RemoveAt(fileLines.Count - 1);
            }
            fileLines.Add(
                new StringBuilder()
                    .Append(item.Sym)
                    .Append(Separator)
                    .Append(item.Other)
                    .Append(Environment.NewLine)
                    .ToString()
            );
            File.WriteAllLines(fileName, fileLines);
        }
    }
}

Отсюда должно быть проще играть с List.AsParallel, чтобы проверить, каки с какими параметрами код быстрее.

Также:

  • Вы открываете файл записи дважды
  • Удаление также несколько дорого, в индексе 0больше (однако, если есть несколько элементов, это не может иметь большого значения
  • if(fileNames.Length > 0) бесполезно, используйте для, если список пуст, то он для просто пропустит
  • Вы можете попробовать StringBuilder вместо строковой интерполяции

Я надеюсь, что эти подсказки помогут вам улучшить ваше время и что я что-то не забыл.

Редактировать


В нашем каталоге около 10 000 файлов, поэтому, когда процесс запущен, он передает ошибку, что Процесс не может получить доступ к файлу, потому что он используется другим процессом

Хорошоесть ли апВозможно, что в ваших строках процесса есть дублированные имена файлов?

Если это так, вы можете попробовать простой подход, повторить попытку через несколько миллисекунд, что-то вроде

private const int SleepMillis = 5;
private const int MaxRetries = 3;

public void WriteFile(string fileName, string[] fileLines, int retries = 0)
{
    try
    {
        File.WriteAllLines(fileName, fileLines);
    }
    catch(Exception e) //Catch the special type if you can
    {
        if (retries >= MaxRetries)
        {
            Console.WriteLine("Too many tries with no success");
            throw; // rethrow exception
        }
        Thread.Sleep(SleepMillis);
        WriteFile(fileName, fileLines, ++retries); // try again
    }
}

Я пыталсядля простоты, но есть некоторые аннотации: - Если вы можете сделать ваши методы асинхронными , это может быть улучшением, изменив сон для Task.Delay , но вам нужнохорошо знать и понимать, как работает асинхронность - если коллизия часто случается, вам следует попробовать другой подход, например, параллельную карту с семафорами

Второе редактирование


В реальном сценарии я подключаюсь к websocket и получаю от 70 000 до 1 lac записей каждую минуту, а после этого я раздваиваю эти записи с данными потокового вещания и сохраняю их в своем собственном файле.И это становится медленнее, когда я применяю нашу концепцию с 11 000 файлов

Это сложная проблема, насколько я понимаю, вы говорите о 1166 записях в секунду, при таком размере мелкие детали могутстановятся большими узкими местами.

На этом этапе я думаю, что лучше подумать о других решениях, это может быть столько ввода-вывода для диска, может быть много потоков или слишком мало, сеть ...

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

Вам нужно четко понимать, что вас тормозит, чтобы вы могли атаковать это напрямую, это будет зависеть от многих вещей, с этой частью вам будет сложно помочь :(.

Существует тонн инструментов для профилей приложений c # и множество способов решения этой проблемы (распределение нагрузки на нескольких серверах, использование чего-то вроде redis для очень быстрого сохранения данных, какое-то событиехранить, чтобы вы могли использовать события ....

...