如何一次读写超过 25000 records/lines 到文本文件?
How to read and write more then 25000 records/lines into text file at a time?
我正在使用网络套接字将我的应用程序与股票市场实时数据提供商连接起来。因此,当市场活跃且套接字打开时,它会在一分钟内为我提供近 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 行。那么如何使用所有这些代码增加行执行 time/process 呢?
首先你需要清理你的代码以获得更多可见性,我做了一个快速重构,这就是我得到的
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)
没用,用一个for,如果list为空,那么他for会直接跳过
- 您可以尝试使用 StringBuilder 代替字符串插值
希望这些提示可以帮助您改善时间!而且我没有忘记什么。
编辑
We have nearly 10,000 files in our directory. So when process is
running then it's passing an error that The Process can not access the
file because it is being used by another process
那么,在您的流程中是否有可能存在重复的文件名?
如果是这种情况,您可以尝试一种简单的方法,几毫秒后重试,例如
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
}
}
我尽量保持简单,但有一些注释:
- 如果你可以制作你的方法async, it could be an improvement by changing the sleep for a Task.Delay,但你需要知道并理解异步是如何工作的
- 如果碰撞发生很多,那么你应该尝试另一种方法,比如 semaphores
的并发映射
第二次编辑
In real scenario I am connecting to websocket and receiving 70,000 to
1 lac records on every minute and after that I am bifurcating those
records with live streaming data and storing in it's own file. And
that becomes slower when I am applying our concept with 11,000 files
这是一个难题,据我了解,您说的是每秒 1166 条记录,在这种规模下,小细节可能会成为大瓶颈。
在那个阶段我认为最好考虑其他解决方案,它可能对磁盘来说太多 I/O,可能有很多线程,也可能太少,网络...
您应该首先分析应用程序以检查应用程序在哪些方面花费了更多的时间,使用了多少资源?你有多少资源?内存、处理器、垃圾收集器、网络如何?你有固态硬盘吗?
你需要清楚地了解是什么让你放慢了速度,这样你才能直接攻击它,这将取决于很多事情,这部分很难提供帮助:(。
有tons of tools for profile c# apps,还有很多方法可以解决这个问题(将费用分散在几个服务器上,使用像redis这样的东西来真正快速地保存数据,一些事件存储,这样你就可以使用事件....
我正在使用网络套接字将我的应用程序与股票市场实时数据提供商连接起来。因此,当市场活跃且套接字打开时,它会在一分钟内为我提供近 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 行。那么如何使用所有这些代码增加行执行 time/process 呢?
首先你需要清理你的代码以获得更多可见性,我做了一个快速重构,这就是我得到的
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)
没用,用一个for,如果list为空,那么他for会直接跳过- 您可以尝试使用 StringBuilder 代替字符串插值
希望这些提示可以帮助您改善时间!而且我没有忘记什么。
编辑
We have nearly 10,000 files in our directory. So when process is running then it's passing an error that The Process can not access the file because it is being used by another process
那么,在您的流程中是否有可能存在重复的文件名?
如果是这种情况,您可以尝试一种简单的方法,几毫秒后重试,例如
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
}
}
我尽量保持简单,但有一些注释: - 如果你可以制作你的方法async, it could be an improvement by changing the sleep for a Task.Delay,但你需要知道并理解异步是如何工作的 - 如果碰撞发生很多,那么你应该尝试另一种方法,比如 semaphores
的并发映射第二次编辑
In real scenario I am connecting to websocket and receiving 70,000 to 1 lac records on every minute and after that I am bifurcating those records with live streaming data and storing in it's own file. And that becomes slower when I am applying our concept with 11,000 files
这是一个难题,据我了解,您说的是每秒 1166 条记录,在这种规模下,小细节可能会成为大瓶颈。
在那个阶段我认为最好考虑其他解决方案,它可能对磁盘来说太多 I/O,可能有很多线程,也可能太少,网络...
您应该首先分析应用程序以检查应用程序在哪些方面花费了更多的时间,使用了多少资源?你有多少资源?内存、处理器、垃圾收集器、网络如何?你有固态硬盘吗?
你需要清楚地了解是什么让你放慢了速度,这样你才能直接攻击它,这将取决于很多事情,这部分很难提供帮助:(。
有tons of tools for profile c# apps,还有很多方法可以解决这个问题(将费用分散在几个服务器上,使用像redis这样的东西来真正快速地保存数据,一些事件存储,这样你就可以使用事件....