- vừa được xem lúc

Chọn lựa giải pháp deserialize JSON hiệu quả

0 0 10

Người đăng: Vũ Viết Văn

Theo Viblo Asia

Vấn đề

Việc lưu JSON càng ngày trở lên phổ biến nó cũng như một biện pháp tối ưu cách lưu trữ hiệu quả bởi tính nhỏ gọn, dễ đọc, dễ truyền tải, lưu trữ, tốc độ,... Nhưng cùng đó việc sử dụng tuy rất đơn giản song cũng làm vấn đề rất đau đầu với nhiều người nếu JSON lớn, quá lớn, phức tạp việc deserialize JSON sao cho tối ưu, hiệu quả.

Để đáng giá dùng sao cho hiệu quả và tối ưu vẫn còn là phụ thuộc vào một số yếu tố, bao gồm:

  • Kích thước của dữ liệu JSON
  • Số lần truy cập dữ liệu JSON
  • Tốc độ truy cập dữ liệu JSON
  • Kiểu dữ liệu JSON
  • Kích thước của dữ liệu JSON

Nếu dữ liệu JSON nhỏ, thì việc deserialize JSON sẽ không có tác động đáng kể đến hiệu suất. Tuy nhiên, nếu dữ liệu JSON lớn, thì việc deserialize JSON có thể làm giảm hiệu suất.

Giới thiệu

1. JSON

JSON là viết tắt của JavaScript Object Notation, là một định dạng dữ liệu dựa trên văn bản (text-based data format) để trao đổi dữ liệu giữa các ứng dụng. JSON là một định dạng dữ liệu nhẹ, dễ đọc và dễ viết, và có thể được sử dụng bởi bất kỳ ngôn ngữ lập trình nào.

JSON được cấu tạo từ các cặp "thuộc tính - giá trị". Thuộc tính là một chuỗi, và giá trị có thể là một chuỗi, một số, một mảng, hoặc một đối tượng.

Ví dụ:

{ "name": "John Doe", "age": 30, "address": { "street": "123 Main Street", "city": "San Francisco", "state": "CA", "zip": "94102" }
}

JSON có thể được sử dụng để lưu trữ dữ liệu trong các tệp, hoặc để truyền dữ liệu giữa các ứng dụng. JSON thường được sử dụng trong các ứng dụng web, API, và các dịch vụ đám mây.

Nhìn chung, JSON là một định dạng dữ liệu linh hoạt và hiệu quả được sử dụng rộng rãi trong nhiều ngữ cảnh khác nhau.

2. Deserialize JSON

Deserialize JSON là quá trình chuyển đổi một chuỗi văn bản JSON (JavaScript Object Notation) thành một cấu trúc dữ liệu trong ngôn ngữ lập trình mà bạn đang sử dụng.

Nói một cách đơn giản hơn, JSON giống như một loại ngôn ngữ "dễ đọc với con người" để lưu trữ dữ liệu được sắp xếp. Deserialization giúp "dịch" nội dung này thành một định dạng mà máy tính có thể hiểu, chẳng hạn như các đối tượng, mảng, chuỗi, số, ... trong ngôn ngữ lập trình cụ thể.

Ví dụ :

// Nhận chuỗi JSON
string json = "{ \"data\": [ { \"id\": 1, \"name\": \"John Doe\", \"age\": 30 }, { \"id\": 2, \"name\": \"Jane Doe\", \"age\": 25 } ]
}"; // Tạo DataTable
DataTable dataTable = new DataTable(); // Thêm các cột vào DataTable
dataTable.Columns.Add("id", typeof(int));
dataTable.Columns.Add("name", typeof(string));
dataTable.Columns.Add("age", typeof(int)); // Deserialize JSON
JsonConvert.DeserializeObject(json, dataTable);

Triển khai

Việc JSON nhỏ và vừa, đơn giản. Bạn có thể sử dụng phương thức DeserializeObject() của thư viện JSON để lấy từng giá trị riêng lẻ từ JSON. Đây là cách phổ biến mà các anh em dev hay dùng nhất.

Ví dụ:

string json = "{"id": 1, "name": "John Doe", "age": 30}"; var person = JsonConvert.DeserializeObject<Person>(json); Console.WriteLine(person.Id); // 1
Console.WriteLine(person.Name); // John Doe
Console.WriteLine(person.Age); // 30 

Tuy nhiên khi JSON lớn, quá lớn và phức tạp thì việc sử dụng phương thức DeserializeObject() không có hiệu quả, tối ưu, có thể Error ⛔️. Lúc này ta cần phải xác định cấu trúc JSON. Điều này sẽ giúp bạn lựa chọn cách deserialize phù hợp và tối ưu hóa hiệu suất.

Sử dụng các công cụ tối ưu hóa hiệu suất

Có một số công cụ tối ưu hóa hiệu suất của C# có thể giúp cải thiện hiệu suất deserialize JSON. Bạn có thể sử dụng công cụ PerfView để đo lường hiệu suất của quá trình deserialize JSON và xác định các khu vực có thể được tối ưu hóa.

Công cụ PerfView là một công cụ hiệu suất của Microsoft cho phép chúng ta đo lường hiệu suất của ứng dụng. Công cụ này có thể được sử dụng để đo lường hiệu suất của quá trình deserialize JSON và xác định các khu vực có thể được tối ưu hóa.

Các trình theo dõi sau vào dự án của bạn:

  • Process CPU Usage
  • Memory Usage
  • I/O Activity

Dưới đây là một số chỉ số bạn có thể xem xét để xác định các khu vực có thể được tối ưu hóa:

  • Tỷ lệ sử dụng CPU
  • Tỷ lệ sử dụng bộ nhớ
  • Số lượng I/O
  • Thời gian thực hiện

➡️ Nếu bạn thấy rằng tỷ lệ sử dụng CPU cao, điều đó có nghĩa là quá trình deserialize JSON đang sử dụng nhiều CPU. Bạn có thể cố gắng tối ưu hóa mã của mình để giảm thiểu việc sử dụng CPU.

➡️ Nếu bạn thấy rằng tỷ lệ sử dụng bộ nhớ cao, điều đó có nghĩa là quá trình deserialize JSON đang sử dụng nhiều bộ nhớ. Bạn có thể cố gắng tối ưu hóa mã của mình để giảm thiểu việc sử dụng bộ nhớ.

➡️ Nếu bạn thấy rằng số lượng I/O cao, điều đó có nghĩa là quá trình deserialize JSON đang thực hiện nhiều I/O. Bạn có thể cố gắng tối ưu hóa mã của mình để giảm thiểu việc thực hiện I/O.

➡️ Nếu bạn thấy rằng thời gian thực hiện cao, điều đó có nghĩa là quá trình deserialize JSON đang mất nhiều thời gian để hoàn thành. Bạn có thể cố gắng tối ưu hóa mã của mình để giảm thiểu thời gian thực hiện.

Dưới đây là một số các giải pháp tối ưu hóa hiệu suất

1. Sử dụng các thư viện chuyên dụng

Các thư viện chuyên dụng như Newtonsoft.Json, Json.NET, ServiceStack.Text.Json được thiết kế để xử lý JSON hiệu quả hơn so với các cách tiếp cận thông thường như sử dụng chuỗi ký tự.

Thư viện Newtonsoft.Json cung cấp một số tính năng giúp cải thiện hiệu suất deserialize JSON, chẳng hạn như:Caching, Lazy loading, Parallel processing Bạn có thể sử dụng các tính năng này để cải thiện hiệu suất deserialize JSON.

Do Newtonsoft.Json và Json.NET đã quá phổ biến và được nhiều người sử dụng, nên tôi thiên về ServiceStack.Text.Json.

ServiceStack.Text.Json cung cấp một số tính năng nâng cao để giúp cải thiện hiệu suất deserialize JSON. Một số tính năng này bao gồm: Lazy loading, Parallel processing, Caching.

1.1 Lazy loading

Lazy loading trong ServiceStack.Text.Json có thể tải các thuộc tính của đối tượng JSON một cách tải chậm, bạn cần sử dụng lớp LazyLoadSerializer. Điều này có thể giúp cải thiện hiệu suất nếu không phải tất cả các thuộc tính của đối tượng JSON đều được sử dụng.

Ví dụ :

using ServiceStack.Text.Json; LazyLoadSerializer serializer = new LazyLoadSerializer(); Person person = serializer.Deserialize<Person>(json); Console.WriteLine(person.Id); // 1

2.2 Parallel processing

Parallel processing trong ServiceStack.Text.Json có thể sử dụng xử lý song song để deserialize JSON, bạn cần sử dụng lớp ParallelSerializer. Điều này có thể giúp cải thiện hiệu suất nếu JSON lớn.

Ví dụ :

using ServiceStack.Text.Json; ParallelSerializer serializer = new ParallelSerializer(); Person[] people = serializer.Deserialize<Person>(json); foreach (var person in people)
{ Console.WriteLine(person.Id);
}

3.3 Caching

Caching trong ServiceStack.Text.Json có thể sử dụng bộ nhớ đệm để lưu trữ các giá trị JSON đã được deserialize. Điều này có thể giúp cải thiện hiệu suất nếu JSON được deserialize nhiều lần. Để sử dụng bộ nhớ đệm, bạn cần định cấu hình bộ nhớ đệm bằng cách sử dụng lớp CacheProvider. Đây là tính năng nâng cao của ServiceStack.Text.Json

Ví dụ :

using ServiceStack.Text.Json;
using ServiceStack.Cache; CacheProvider cacheProvider = new MemcachedCacheProvider(); ServiceStack.Text.Json.SerializerSettings settings = new ServiceStack.Text.Json.SerializerSettings
{ CacheProvider = cacheProvider
};

Sau khi định cấu hình bộ nhớ đệm, bạn có thể sử dụng phương thức Deserialize() với tùy chọn cache để lưu trữ giá trị JSON đã được deserialize vào bộ nhớ đệm.

using ServiceStack.Text.Json;
using ServiceStack.Cache; CacheProvider cacheProvider = new MemcachedCacheProvider(); ServiceStack.Text.Json.SerializerSettings settings = new ServiceStack.Text.Json.SerializerSettings
{ CacheProvider = cacheProvider
}; Person person = Deserialize<Person>(json, settings, true);

2. Phân tích JSON thành các phần nhỏ

Nếu JSON quá lớn, bạn có thể phân tích nó thành các phần nhỏ hơn để deserialize. Điều này sẽ giúp giảm tải cho hệ thống và cải thiện hiệu suất.

2.1.Chunk

Bạn có thể sử dụng các phương thức như Chunk() của thư viện LINQ để phân tích JSON thành các phần nhỏ. Phương thức này có thể được sử dụng với các đối tượng JSON có cấu trúc dạng mảng. Phương thức Chunk() có định nghĩa như sau:

public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunkSize)
Phương thức này có hai tham số: source: Một mảng hoặc IEnumerable của các đối tượng T.
chunkSize: Kích thước của mỗi phần nhỏ.

Chúng ta có thể sử dụng phương thức Chunk() để phân tích JSON thành các phần nhỏ như sau:

using System;
using System.Linq; string json = "[ {"id": 1, "name": "John Doe", "age": 30}, {"id": 2, "name": "Jane Doe", "age": 25}, {"id": 3, "name": "Mary Johnson", "age": 20}
]"; var people = JsonSerializer.Deserialize<List<Person>>(json); var chunks = people.Chunk(2); foreach (var chunk in chunks)
{ foreach (var person in chunk) { Console.WriteLine(person.Id); }
} 

2.2. Split

Split cắt nhỏ chuỗi JSON thành các phần nhỏ hơn để deserialize sẽ hiệu quả hơn
Bạn có thể sử dụng phương thức Split() của chuỗi ký tự để phân tích JSON thành các phần nhỏ như sau:

string json = "{"data": [{"id": 1, "name": "John Doe", "age": 30}, {"id": 2, "name": "Jane Doe", "age": 25}]}"; var data = json.Split(',').Select(x => JsonConvert.DeserializeObject<Person>(x));

Trong ví dụ này, phương thức Split() sẽ phân tích JSON thành một mảng các chuỗi. Sau đó, phương thức Select() sẽ sử dụng mỗi chuỗi để deserialize một đối tượng Person

3. Sử dụng bộ nhớ đệm

Bộ nhớ đệm cho phép chúng ta lưu trữ các giá trị JSON đã được deserialize, điều này có thể giúp giảm thiểu việc truy cập vào cơ sở dữ liệu hoặc tải lên từ Internet. Bạn có thể sử dụng bộ nhớ đệm để lưu trữ các giá trị JSON đã được deserialize bằng cách sử dụng các lớp Cache hoặc Dictionary của C#.

Dưới đây là một số lưu ý khi sử dụng bộ nhớ đệm để deserialize JSON:

  • 🔰 Chúng ta cần chọn bộ nhớ đệm phù hợp với nhu cầu của ứng dụng. Một số loại bộ nhớ đệm phổ biến bao gồm bộ nhớ đệm RAM, bộ nhớ đệm ảo, và bộ nhớ đệm phân tán.
  • 🔰 Chúng ta cần xác định thời gian tồn tại của các giá trị JSON trong bộ nhớ đệm. Chúng ta có thể sử dụng thời gian tồn tại tĩnh hoặc thời gian tồn tại động.
  • 🔰 Chúng ta cần định kỳ xóa các giá trị JSON không còn sử dụng trong bộ nhớ đệm. Điều này sẽ giúp tránh lãng phí bộ nhớ.

Ví dụ:

using System.Collections.Generic;
using System.Collections.Concurrent; public class MyClass
{ private static readonly ConcurrentDictionary<string, Person> _cache = new ConcurrentDictionary<string, Person>(); public Person GetPerson(string id) { if (_cache.ContainsKey(id)) { return _cache[id]; } // Deserialize JSON var person = JsonConvert.DeserializeObject<Person>(json); // Cache the person _cache[id] = person; return person; }
}

Có một số vấn đề có thể xảy ra khi deserialize JSON

  • Lỗi cú pháp: Nếu JSON không đúng cú pháp, quá trình deserialize sẽ thất bại. Điều này có thể xảy ra do lỗi nhập liệu, lỗi mã hóa, hoặc lỗi cấu trúc dữ liệu.
  • Lỗi định dạng: Nếu JSON không đúng định dạng, quá trình deserialize cũng sẽ thất bại. Điều này có thể xảy ra do sử dụng các ký tự đặc biệt không được hỗ trợ, hoặc sử dụng các định dạng không được hỗ trợ.
  • Lỗi giá trị: Nếu giá trị JSON không phù hợp với kiểu dữ liệu được mong đợi, quá trình deserialize cũng sẽ thất bại. Điều này có thể xảy ra do nhập liệu sai, hoặc do sử dụng các định dạng không được hỗ trợ.
  • Lỗi tham chiếu: Nếu JSON tham chiếu đến một đối tượng không tồn tại, quá trình deserialize cũng sẽ thất bại. Điều này có thể xảy ra do lỗi nhập liệu, hoặc do sử dụng các định dạng không được hỗ trợ.

Để tránh các vấn đề này, bạn nên đảm bảo rằng JSON được nhập liệu chính xác, được định dạng đúng, và sử dụng các ký tự và định dạng được hỗ trợ. Bạn cũng nên kiểm tra JSON trước khi deserialize để đảm bảo rằng không có lỗi.

  • ✔️Sử dụng các công cụ kiểm tra cú pháp để xác minh JSON trước khi deserialize.
  • ✔️Sử dụng các công cụ định dạng để định dạng JSON trước khi deserialize.
  • ✔️Sử dụng các thư viện JSON có hỗ trợ kiểm tra lỗi.

Kết luận

Như vậy, mình vừa giới thiệu đến các bạn các giải pháp có thể tối ưu hiệu deserialize JSON. Hy vọng, qua bài viết này, các bạn sẽ nắm được chi tiết và sử dụng chúng cho nhu cầu của mình một cách phù hợp. Nếu mọi người có giải pháp hay hơn có thể đóng góp dưới phần Bình luận mình xin tiếp thu các ý kiến của mọi người đóng góp
Cảm ơn các bạn đã theo dõi bài viết của mình và mong rằng các bạn sẽ tiếp tục ủng hộ những bài viết tiếp theo của mình nhé!

Bình luận

Bài viết tương tự

- vừa được xem lúc

Caching đại pháp 2: Cache thế nào cho hợp lý?

Caching rất dễ. Mình không nói đùa đâu, caching rất là dễ. Ai cũng có thể làm được chỉ sau 10 phút đọc tutorial. Nó cũng giống như việc đứa trẻ lên 3 đã có thể cầm bút để vẽ vậy.

0 0 126

- vừa được xem lúc

Instagram - Thiết Kế Hệ Thống có gì hay? ?

Thiết Kế Hệ Thống tương tự Instagram có khó? và những điều cần lưu ý. Xin chào, mình là Khanh Ney, 1 Backend Developer chính hiệu sùng bái các vị Vua và mang tư duy của các vị Vua giải quyết vấn đề với DIY (Do it Yourself).

0 0 43

- vừa được xem lúc

Caching đại pháp 3: Vấn đề và cách giải quyết

Vấn đề không tự sinh ra cũng không tự mất đi, nó chỉ chuyển từ dạng này sang dạng khác, hoặc từ chỗ này sang chỗ khác. Đó là cách mọi thứ hoạt động.

0 0 128

- vừa được xem lúc

Performance Optimization 106: Caching - con đường lắm chông gai

Con đường vươn tới những hệ thống tải cao đầy chông gai và cỏ dại. Caching luôn là một con đường chông gai bởi vì nó không có hồi kết.

0 0 99

- vừa được xem lúc

[Redis] - Giải pháp xử lý 300 triệu bản ghi với Redis

Đây là câu chuyện về 1 lần chuyển đổi hệ thống của Instagram. .

0 0 35

- vừa được xem lúc

[Redis] - 7 sai lầm thường gặp khi làm việc với Redis.

1. Không sử dụng mật khẩu.

0 0 35