문제

나는이 질문을 알고있다 가지다 계속 ~ 이다 완료 그러나 나는 그것에 약간 다른 비틀기를 가지고 있습니다. 몇몇은 이것이 조기 최적화라고 지적했으며, 실용성과 실용성을 요구한다면 전적으로 사실입니다. 내 문제는 실제적인 문제에 뿌리를두고 있지만 그럼에도 불구하고 여전히 궁금합니다.


데이터베이스 스키마 (쉽게 수백 개의 테이블, 뷰 등)를 재현하기 위해 스크립트를 만들기 위해 많은 SQL 문을 만들기 위해 스크립트를 만들기 위해 스크립트를 작성합니다. 이것은 내 문자열 연결이 부록 전용임을 의미합니다. MSDN에 따르면 StringBuilder는 내부 버퍼를 유지하여 작동합니다 (CHAR []). 문자열 문자를 복사합니다 그것으로 그리고 재 할당 필요에 따라 배열.

그러나 내 코드에는 반복 문자열이 많이 있습니다 ( "Create Table [", "Go N"등)에는이를 활용할 수 있습니다. 인턴 그러나 StringBuilder가 매번 복사되므로 사용하는 경우는 아닙니다. 유일한 변수는 본질적으로 테이블 이름이며 이미 메모리에있는 다른 객체의 문자열로 이미 존재합니다.

그래서 내 데이터를 읽고 스키마 정보를 보유하는 객체를 작성한 후에 내 문자열 정보를 인테닝으로 재사용 할 수 있다고 말할 수 있습니다.

그렇다면 문자열의 목록이나 링크 사역 목록이 인턴 된 현에 포인터를 유지하기 때문에 더 빠르지 않습니까? 그런 다음 정확히 올바른 길이 인 전체 문자열의 단일 메모리 할당에 대해 String.concat ()로의 호출 일뿐입니다.

목록은 인턴 된 포인터의 문자열 []를 재 할당해야하며 링크 된 목록은 노드를 만들고 포인터를 수정해야하므로 "무료"는 아니지만 내가 할 수있는 경우가 아니라면 수천 개의 인턴 끈을 연결합니다 그러면 그들은 더 효율적일 것 같을 것입니다.

이제 각 SQL 문에 대한 캐릭터 카운트에 대한 휴리스틱을 제시하고 각 유형을 계산하고 대략적인 아이디어를 얻고 문자열 재산 용량을 사전 설정하여 char []를 재 할당하지 않도록 내 StringBuilder 용량을 사전 설정할 수 있다고 생각하지만 [] 재 할당 확률을 줄입니다.

따라서이 경우 단일 연결 문자열을 얻는 데 가장 빠릅니다.

  • StringBuilder
  • 목록u003Cstring> 인턴 된 줄의
  • Linkedlistu003Cstring> 인턴 된 줄의
  • 용량 휴리스틱이있는 StringBuilder
  • 다른 것?

A로 별도의 질문 (항상 디스크로 이동하지는 않을 수 있습니다) 위의 것 : 출력 파일의 단일 스트림 라이터가 아직 더 빠르겠습니까? 또는 목록이나 LinkedList를 사용한 다음 메모리에서 먼저 연결하는 대신 목록에서 파일에 작성하십시오.

편집하다:요청대로 참조 (.NET 3.5)에서 MSDN에서. 그것은 말한다 : "객실을 사용할 수있는 경우 새 데이터가 버퍼 끝에 추가됩니다. 그렇지 않으면 새롭고 더 큰 버퍼가 할당됩니다. 원래 버퍼의 데이터가 새 버퍼에 복사되고 새 데이터가 새 버퍼에 추가됩니다." 그것은 나에게 더 크게 만들기 위해 재 할당 된 char []를 의미합니다 (오래된 데이터를 크기 조정 어레이에 복사해야 함).

도움이 되었습니까?

해결책

당신을 위해 별도의 질문, win32는 a 쓰기 파일 기능은 디스크에 (인턴 된) 문자열의 목록을 효율적으로 쓸 수 있지만, 디스크 쓰기가 매우 큰 동의를 제외하고는 모두를 어둡게하기 때문에 비동기 적으로 호출 될 때만 주목할만한 차이를 만듭니다.

당신을 위해 주요 질문: 메가 바이트의 대본이나 수만 개의 스크립트에 도달하지 않는 한 걱정하지 마십시오.

StringBuilder가 각 재 할당에서 할당 크기를 두 배로 늘릴 것으로 기대할 수 있습니다. 이는 256 바이트에서 1MB에서 1MB까지 버퍼를 성장시키는 것이 단지 12 개의 재 할당입니다. 초기 추정치가 대상에서 3 배의 순서가 3 배라는 점을 감안할 때 상당히 좋습니다.

순전히 운동으로서 일부 추정치 : 1MB의 버퍼를 구축하면 약 3MB 메모리 (1MB 소스, 1MB 대상, 재 할당 중 복사로 인한 1MB)가 휩쓸립니다.

링크 된 목록 구현은 약 2MB를 휩쓸고 문자열 참조 당 8 바이트 / 객체 오버 헤드를 무시합니다). 따라서 10GBIT/S 및 1MB L2 캐시의 일반적인 메모리 대역폭과 비교하여 1MB 메모리 읽기/쓰기를 저장하고 있습니다.)

예, 목록 구현이 잠재적으로 더 빠르며, 버퍼가 크기가 크면 차이가 중요합니다.

소형 문자열의 훨씬 더 일반적인 경우에, 알고리즘 이득은 무시할 수 있으며 다른 요인들에 의해 쉽게 상쇄됩니다. StringBuilder 코드는 이미 코드 캐시에있을 가능성이 높으며, 마이크로 옵스 최적화를위한 실행 가능한 대상이 될 수 있습니다. 또한 문자열을 내부적으로 사용한다는 것은 최종 문자열이 초기 버퍼에 맞는 경우 전혀 사본이 없음을 의미합니다.

링크 된 목록을 사용하면 O (문자 수)에서 O (세그먼트 수)로 재 할당 문제가 표시됩니다. 문자열 참조 목록은 문자열과 동일한 문제에 직면합니다!


따라서 IMO IMO StringBuilder의 구현은 올바른 선택이며 공동 사례에 최적화되며 대부분 예기치 않게 큰 대상 버퍼에 대해 저하됩니다. 목록 구현이 먼저 많은 작은 세그먼트에 대해 저하 될 것으로 예상되는데, 이는 실제로 극단적 인 시나리오 StringBuilder가 최적화하려고합니다.

그럼에도 불구하고 두 아이디어의 비교를 보는 것은 흥미로울 것입니다. 그리고 목록이 더 빠르기 시작할 때.

다른 팁

내가 이와 같은 것을 구현한다면, 나는 stringbuilder (또는 스크립트의 메모리 버퍼에있는 다른 것)를 구축하지 않을 것입니다. 대신 파일로 스트리밍하고 모든 문자열을 인라인으로 만들 것입니다.

다음은 Pseudo 코드의 예입니다 (구문 적으로 정확하지 않거나 무엇이든) :

FileStream f = new FileStream("yourscript.sql");
foreach (Table t in myTables)
{
    f.write("CREATE TABLE [");
    f.write(t.ToString());
    f.write("]");
    ....
}

그런 다음 모든 문자열 복사와 함께 스크립트의 메모리 표현이 필요하지 않습니다.

의견?

내 경험상, 나는 StringBuilder가 많은 양의 문자열 데이터에 대해 대부분의 모든 것을 능가했습니다. 재 할당을 방지하기 위해 추정치를 20% 또는 30% 늘림으로써 기억을 낭비하는 것이 좋습니다. 나는 현재 내 자신의 데이터를 사용하여 백업하기 어려운 숫자가 없지만 살펴보십시오. 자세한 내용은이 페이지입니다.

그러나 Jeff가 지적하는 것을 좋아하기 때문에 조기 최적화하지 마십시오!

편집 : @Colin Burnett가 지적한 것처럼 Jeff가 수행 한 테스트는 Brian의 테스트에 동의하지 않지만 Jeff의 게시물을 연결하는 요점은 일반적으로 조기 최적화에 관한 것입니다. Jeff의 페이지에 대한 몇몇 의견 제시 자들은 그의 테스트와 관련된 문제를 언급했습니다.

실제로 StringBuilder 인스턴스를 사용합니다 String 내부적. String 실제로는 변이합니다 System 어셈블리이기는 이유입니다 StringBuilder 그 위에 구축 될 수 있습니다. 당신은 할 수 있습니다 StringBuilder 인스턴스를 만들 때 합리적인 길이를 할당하여 더 효과적입니다. 이렇게하면 크기 조정 작업 수를 제거/줄입니다.

문자열 인턴은 컴파일 시간에 식별 할 수있는 문자열에 대해 작동합니다. 따라서 실행 중에 많은 문자열을 생성하면 String에서 인턴 메소드를 호출하여 직접 그렇게하지 않으면 인턴이되지 않습니다.

인턴은 문자열이 동일 한 경우에만 도움이됩니다. 거의 동일한 문자열은 인턴으로부터 혜택을받지 않습니다 "SOMESTRINGA" 그리고 "SOMESTRINGB" 인턴이 있더라도 두 개의 다른 줄이 될 것입니다.

연결중인 문자열의 모든 (또는 대부분)가 인턴 인 경우, 체계가 유력하게 메모리를 덜 사용할 수 있고 몇 개의 큰 문자열 사본을 절약 할 수 있으므로 성능 향상을 줄 수 있습니다.

그러나 실제로 성능이 향상되는지 여부는 처리중인 데이터의 양에 따라 다릅니다. 개선은 알고리즘의 크기가 아닌 일정한 요인이기 때문입니다.

실제로 말할 수있는 유일한 방법은 두 가지 방법을 사용하여 앱을 실행하고 결과를 측정하는 것입니다. 그러나 메모리 압력이 심하고 바이트를 절약 할 수있는 방법이 필요하지 않으면 귀찮게하지 않고 String Builder를 사용합니다.

StringBuilder 사용하지 않습니다 char[] 데이터를 저장하려면 내부 변동성 문자열을 사용합니다. 즉, 문자열 목록을 연결할 때와 같이 최종 문자열을 만들기위한 추가 단계가 없음을 의미합니다. StringBuilder 내부 문자열 버퍼를 일반 문자열로 반환합니다.

그 재 할당 StringBuilder 용량을 높이기 위해 데이터는 데이터가 평균적으로 1.33 배 더 복사된다는 것을 의미합니다. 당신이 만들 때 크기에 대해 좋은 견적을 제공 할 수 있다면 StringBuilder 당신은 그 모피를 줄일 수 있습니다.

그러나 약간의 관점을 얻으려면 최적화하려는 것이 무엇인지 살펴 봐야합니다. 프로그램에서 대부분의 시간이 걸리는 것은 실제로 데이터를 디스크에 작성하는 것입니다. StringBuilder (거의 가능성이 낮음), 전반적인 차이는 여전히 몇 %에 불과합니다.

이것에 대해 C ++를 고려 했습니까? C ++로 작성된 T/SQL 표현식을 이미 구축하는 라이브러리 클래스가 있습니까?

현에 대해 가장 느린 것은 malloc입니다. 32 비트 플랫폼에서 문자열 당 4KB가 필요합니다. 생성 된 문자열 객체 수를 최적화하는 것을 고려하십시오.

C#을 사용해야하는 경우 다음과 같은 것을 권장합니다.

string varString1 = tableName;
string varString2 = tableName;

StringBuilder sb1 = new StringBuilder("const expression");
sb1.Append(varString1);

StringBuilder sb2 = new StringBuilder("const expression");
sb2.Append(varString2);

string resultingString = sb1.ToString() + sb2.ToString();

나는 컴퓨터가 종속성 주입 프레임 워크를 사용한 객체 인스턴스화를위한 최상의 경로를 평가하게하는 한, Perf가 그렇게 중요하다면 갈 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top