紧跟上篇文章 十个进程开启十个bash后一致写入命令执行完毕之后产生了很多很多的文件,博主需要对这些文件同意处理,也就是说对几十万个文件进行处理,想了又想,单线程处理那么多数据肯定不行,于是乎想到了使用多线程,紧接着就引发了一系列问题,其中做大的问题就是json序列化,导致了多条线程运行和单线程运行时间一致问题。
我们正常去读取json文件转成一般是通过实体类去使用JsonConvert.DeserializeObject方法进行接收的,然后再通过实体类去进行一系列的操作,目前遇到的问题就是读取上万的json文件进行反序列化与序列化进行操作,如果一条一条的去操作的话速度可谓是非常非常慢,然后经过大佬的推荐和自己了解决定使用微软专门推出的一个操作json的类。
这个类说的也非常清楚,提供高性能、低分配和标准兼容的功能,以处理 JavaScript 对象表示法 (JSON),其中包括将对象序列化为 JSON 文本以及将 JSON 文本反序列化为对象(内置 UTF-8 支持)。 它还提供类型以用于读取和写入编码为 UTF-8 的 JSON 文本,以及用于创建内存中文档对象模型 (DOM) 以在数据的结构化视图中随机访问 JSON 元素。
虽然这个类库专门针对于性能来优化的,但是使用起来往往非常的困难,没有我们大众所使用的JsonConvert.DeserializeObject方便,但是如像我一样对待性能有极致的要求的话,可以使用这个类库,用法也非常简单,下面我给出例子
引入命名空间:
System.Text.Json
那么具体如何使用呢?我这里给出具体的使用方法以及详细的例子。
JsonDocument document1 = null; StreamReader f2 = new StreamReader(filePath, Encoding.UTF8); String line; while ((line = f2.ReadLine()) != null) { document1 = JsonDocument.Parse(line); } f2.Close(); f2.Dispose();
这里我们去读取filepath,filepath是json文件路径。我们使用 JsonDocument.Parse对json文件进行操作。这个方法表示单个 JSON 字节值的 UTF-8 编码文本形式的序列分析为 JsonDocument。
把json文件序列分析为JsonDocument类型了下面就是对这个类型进行操作,为什么现在好多人不喜欢使用这种方法,大概率是因为取值比较难
对于JsonDocument如何取出我们想要的值或者节点呢?看下面的例子:
{ "ClassName": "Science", "Teacher/u0027s Name": "Jane", "Semester": "2019-01-01", "Students": [ { "Name": "John", "Grade": 94.3 }, { "Name": "James", "Grade": 81.0 }, { "Name": "Julia", "Grade": 91.9 }, { "Name": "Jessica", "Grade": 72.4 }, { "Name": "Johnathan" } ], "Final": true }
上述是一个json文件内的数据,我们解析JsonDocument如何解析出Class Name节点值呢?
可以使用如下操作
//定义变量去接收 var className = "0"; //判断我们解析出来的JsonDocument是否为空 if (document1 != null) { JsonElement root = document1.RootElement; className = root.TryGetProperty("ClassName", out var temp) ? temp.GetInt32().ToString() : "0"; }
首先使用 JsonDocument.RootElement属性 获取此 JSON 文档的根元素。
对于根元素进行解析,JsonElemet.TryGetProperty() 查找当前对象中名为 ClassName 的属性,返回一个指示此类属性是否存在的值。 如果此属性存在,会将其值分配给 value
参数。现在value参数对应temp,解析时还应注意属性值类型,如果为string类型则使用GetString(),去进行转换,int类型可以使用GetInt32(),进行转换,具体其他类型可以查看微软官方给出的类型。
使用TryGetProperty()方法有什么好处呢?
可以去判断json文件内有没有当前的属性,如果有的话,去返回属性值,无,则返回null。
现在我们取单独属性已经会了,那么如何取数组呢?如何取数组对象呢?
例子:
double sum = 0; int count = 0; using (JsonDocument document = JsonDocument.Parse(jsonString)) { JsonElement root = document.RootElement; JsonElement studentsElement = root.GetProperty("Students"); count = studentsElement.GetArrayLength(); foreach (JsonElement student in studentsElement.EnumerateArray()) { if (student.TryGetProperty("Grade", out JsonElement gradeElement)) { sum += gradeElement.GetDouble(); } else { sum += 70; } } } double average = sum / count; Console.WriteLine($"Average grade : {average}");
上面这个例子是微软官方给出的例子,但是使用与我们已经知道json文件格式的情况。
使用之前我们可以使用TryGetProperty方法先判断json属性是否存在,存在的话去定义一个value值进行接收,先判断是否为存在,存在则把value值进行遍历,然后再去判断这个数组内的属性是否存在,存在的话返回属性值,以此类推便可以拿到所有的json文件中的属性值啦!
性能提升:说了这么多到底这种方法能够提升多少速度呢,经过博主测试JsonConvert.DeserializeObject方法在线程或者进程内使用的话开启多个和单个线程(进程)速度相差基本不大,就好比我开了十个线程,去读取十万个文件,结果和单个线程去读取十万个文件相差几秒??是不是非常离谱。
换用这种高性能处理json文件的类库之后,开启十个线程去操作文件速度直接减少了三分之二!!!!!!