JSON 퍼스 최적화
목적
· 현재 서버 API의 응답을 구문 분석하는 JSON 라이브러리가 느리다고 느끼고 있으므로 뭔가 할 수 없는지 검토하고 싶다
・더 빠른 라이브러리가 있다고 생각하지만 라이브러리를 교환하면 꽤 이런 작업이 되기 때문에 지금 그대로 해보고 싶다
・본래라면 JSON을 없애고 gRPC 같은 것을 사용하고 싶지만 아무도 바꾸는 작업이 크기 때문에 현재의 것을 개선할 수 있으면 좋다
문자열 할당을 줄이세요.
처음에 클래스를 열어 보면 string의 할당이 많다고 생각했습니다. string 가 생성자 에게 건네져 퍼스 하면서 string.substring() 를 이용해 건간 재귀 호출이 되어 버립니다.
list.Add(new JSONObject(str.Substring(start, end)));
json이 깊어질수록 이것이 부르는 횟수가 많아지더라도 원래의 string보다 메모리가 상당히 부풀어요. 퍼스가 느린 뿐만 아니라 GC도 많이 달리게 됩니다.
만약 다음 객체가 string이 아니면 string화하지 않아도 되는 것 아닌가?
1개씩의 char를 체크해 다음의 데이터가 true, false, null, 숫자등이라면 substring의 호출을 날려 보자.
의사 코드:
private static readonly char[] ms_digits = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '-', 'e', 'E' };
private JSONObject parseSubString(string str, int start, int length){
//true, false, nullなどのタイプをチェック
if(length == 4 && (str[start]=='t' || str[start]=='T')){
//true
return new JSONObject(true);
}
if(length == 5 && (str[start]=='f' || str[start+1]=='F')){
//false
return new JSONObject(false);
}
if(length == 4 && (str[start]=='n' || str[start+1]=='N')){
//null
return new JSONObject(Type.NULL);
}
bool isNumber = false;
for(int i=0;i<length;i++){
//ms_digitsに入ったらindex返す
int numIdx = GetNumberFromChar(nextChar);
//数字じゃないならやめる
if(numIdx < 0){ isNumber = false; break;}
// hogehoge
//1個ずつの数字を追加していく
//num = (num*10)+numIdx 的な感じ
// マイナス、少点数などの対応も忘れずに
}
//数字を返す
if(isNumber)
return new JSONObject(number);
//結局stringかオブジェクトだったらsubstringしちゃうかー
return new JSONObject(str.Substring(start, length));
}
이것을 구현하면 substring을 부르는 횟수가 줄어들 것입니다!
덧붙여서 같은 로직을 사용해 StringBuilder에서도 확장할 수 있습니다!
Gavin Pugh 님이 만들어 준 h tp // w w. 가 v푸gh. 이 m / 그렇게 r세 / St 링 g 뭉치 l로 되어 xt ぬめり c. cs 를 참고해 주세요
더 줄일 수 있을까요?
상기라고 어느 정도 string 할당을 줄였지만 아직 json 객체나 배열 등이 substring에 들어온다. 최종 문자열 객체 만 할당 할 수 있습니까?
현재의 라이브러리라면 string가 받는 constructor 밖에 없지만, 이것 MemoryStream이라면 어떨까?
원래
public JSONObject(string str)
생성자가 아니라 새롭게
public JSONObject(Stream stream)
를 만들어 보았습니다. 원래의 퍼스 처리를 흉내내면서
stream.Read(buffer,0,1)
1개씩의 char를 체크하면서 json 퍼스 해 간다. 이렇게 하면 할당이 발생할 때는 json 안에 string 타입의 객체가 있을 때만 됩니다.
그렇다면이 MemoryStream은 어디에서 오는가? 문자열을 MemoryStream으로 변환하면 의미가 사라집니다. HTTP 통신 주위의 시스템을 보면 내부에 MemoryStream를 사용하고 있습니다! 지금까지는 통신이 끝나면 이 MemoryStream이 byte[]로 변환되어 있었지만 그것을 날려 직접 Json에 건네주면 더욱 쾌적. 꽤 큰 통신도 있으므로 이 byte[] 변환이 필요하지 않으면 GC 등도 개선됩니다.
결과
이쪽의 테스트 환경에서 시험해 보았지만 원래 1.25초 걸린 것이 0.25초가 되었습니다! 5배잖아!
역시 쓸데없는 것을 깎아 봅시다
Reference
이 문제에 관하여(JSON 퍼스 최적화), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/clane/items/1b7252b15b2404f99d0a
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
list.Add(new JSONObject(str.Substring(start, end)));
private static readonly char[] ms_digits = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '-', 'e', 'E' };
private JSONObject parseSubString(string str, int start, int length){
//true, false, nullなどのタイプをチェック
if(length == 4 && (str[start]=='t' || str[start]=='T')){
//true
return new JSONObject(true);
}
if(length == 5 && (str[start]=='f' || str[start+1]=='F')){
//false
return new JSONObject(false);
}
if(length == 4 && (str[start]=='n' || str[start+1]=='N')){
//null
return new JSONObject(Type.NULL);
}
bool isNumber = false;
for(int i=0;i<length;i++){
//ms_digitsに入ったらindex返す
int numIdx = GetNumberFromChar(nextChar);
//数字じゃないならやめる
if(numIdx < 0){ isNumber = false; break;}
// hogehoge
//1個ずつの数字を追加していく
//num = (num*10)+numIdx 的な感じ
// マイナス、少点数などの対応も忘れずに
}
//数字を返す
if(isNumber)
return new JSONObject(number);
//結局stringかオブジェクトだったらsubstringしちゃうかー
return new JSONObject(str.Substring(start, length));
}
public JSONObject(string str)
public JSONObject(Stream stream)
stream.Read(buffer,0,1)
Reference
이 문제에 관하여(JSON 퍼스 최적화), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/clane/items/1b7252b15b2404f99d0a텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)