집 >백엔드 개발 >C#.Net 튜토리얼 >.NET의 성능 향상에 대한 자세한 살펴보기
.NET 4.6은 성능 향상과 관련된 일부 CLR 기능을 제공합니다. 이러한 기능 중 일부는 자동으로 적용되지만 SIMD 및 Async Local Storage와 같은 다른 기능은 애플리케이션 작성 방식을 변경해야 합니다.
Mono 팀은 단일 명령 스트림 다중 데이터 스트림 기능인 SIMD에 대한 지원을 항상 자랑스럽게 생각합니다. SIMD는 동시에 최대 8개의 값에 대해 동일한 작업을 수행할 수 있는 CPU 명령어 세트입니다. .NET CLR 버전 4.6이 출시되면서 Windows 개발자는 마침내 이 기능을 사용할 수 있게 되었습니다.
실제로 SIMD의 효과를 관찰하려면 이 예를 참조하면 됩니다. 세 번째 배열을 얻기 위해 c[i] = a[i] + b[i] 형식으로 두 개의 배열을 추가해야 한다고 가정합니다. SIMD를 사용하면 다음과 같은 방법으로 코드를 작성할 수 있습니다.
for (int i = 0; i < size; i += Vector.Count) { Vectorv = new Vector(A,i) + new Vector(B,i); v.CopyTo(C,i); }
이 루프가 Vectorint.Count의 값(CPU 유형에 따라 4 또는 8일 수 있음)만큼 증가하는 방법에 유의하세요. .NET JIT 컴파일러는 해당 코드를 생성하여 CPU에 따라 값이 4 또는 8인 배열을 일괄 추가합니다.
이 방법은 다소 번거로워 보이기 때문에 Microsoft는 다음을 포함한 일련의 보조 클래스도 제공합니다.
Matrix3x2 구조
Matrix4x4 구조
평면구조
쿼터니언 구조
벡터 클래스
벡터(T) 구조
벡터2 구조
Vector3 구조
Vector4 구조
대부분의 개발자는 이 사실을 모릅니다. .NET에서는 동일한 어셈블리를 두 번 로드하는 경우가 많습니다. 이를 위한 조건은 .NET이 먼저 어셈블리의 IL 버전을 로드한 다음 동일한 어셈블리의 NGEN 버전(즉, 미리 컴파일된 버전)을 로드하는 것입니다. 이 접근 방식은 특히 Visual Studio와 같은 대규모 32비트 응용 프로그램의 경우 실제 메모리를 심각하게 낭비합니다.
.NET 4.6에서는 CLR이 NGEN 버전의 어셈블리를 로드하면 해당 IL 버전이 차지하는 메모리가 자동으로 지워집니다.
앞서 .NET 4.0에 도입된 가비지 수집 대기 시간 모드에 대해 설명했습니다. 이 방법은 일정 기간 동안 GC를 완전히 중지하는 것보다 훨씬 안정적이지만 완료 시에는 여전히 충분하지 않습니다.
.NET 4.6에서는 보다 정교한 방법으로 가비지 수집기를 일시적으로 중단할 수 있습니다. 새로운 TryStartNoGCRegion 메서드를 사용하면 작은 개체와 큰 개체에 대해 힙에 필요한 메모리 양을 지정할 수 있습니다.
메모리가 부족하면 런타임은 false를 반환하거나 GC 정리를 통해 충분한 메모리를 얻을 때까지 실행을 중지합니다. TryStartNoGCRegion에 플래그를 전달하여 이 동작을 제어할 수 있습니다. GC 없는 영역에 성공적으로 진입한 경우(프로세스가 끝날 때까지 GC가 허용되지 않음) 프로세스가 끝날 때 EndNoGCRegion 메서드를 호출해야 합니다.
공식 문서에는 이 방법이 스레드로부터 안전한지 여부가 명시되어 있지 않지만 GC의 작동 원리를 고려하면 두 프로세스가 동시에 GC 상태를 변경하려고 시도하는 것을 피해야 합니다.
GC의 또 다른 개선 사항은 고정된 개체(즉, 할당된 후에는 이동할 수 없는 개체)를 처리하는 방식입니다. 문서에는 이 측면이 다소 모호하게 설명되어 있지만 개체의 위치를 수정하면 일반적으로 인접한 개체의 위치도 수정됩니다. Rich Lander는 기사에 다음과 같이 썼습니다.
GC는 고정된 개체를 보다 최적화된 방식으로 처리하므로 GC는 고정된 개체 주변의 메모리를 보다 효과적으로 압축할 수 있습니다. 많은 수의 핀을 사용하는 대규모 애플리케이션의 경우 이러한 변경으로 애플리케이션 성능이 크게 향상됩니다.
GC는 또한 이전 세대에서 메모리 사용 방법에 있어서 더 나은 지능을 보여줍니다. Rich는 계속해서 다음과 같이 썼습니다.
1세대 개체가 2세대 개체로 승격되는 방식도 개선되어 메모리를 보다 효율적으로 사용할 수 있습니다. 한 세대에 새로운 메모리 공간을 할당하기 전에 GC는 먼저 사용 가능한 공간을 사용하려고 시도합니다. 동시에, 사용 가능한 공간 영역을 이용하여 객체를 생성할 때 새로운 알고리즘이 사용되므로 새로 할당된 공간의 크기가 이전보다 객체의 크기에 가까워집니다.
마지막 개선 사항은 성능과 직접적인 관련이 없지만 효과적인 사용을 통해 최적화 결과를 얻을 수 있습니다. 비동기 API가 대중화되기 며칠 전에 개발자는 TLS(스레드 로컬 저장소)를 활용하여 정보를 캐시할 수 있었습니다. TLS는 특정 스레드에 대한 전역 개체처럼 작동합니다. 즉, 일부 컨텍스트 개체를 명시적으로 전달하지 않고도 컨텍스트 정보에 직접 액세스하고 이를 캐시할 수 있습니다.
비동기/대기 모드에서는 스레드 로컬 저장소가 쓸모 없게 됩니다. Wait가 호출될 때마다 다른 스레드로 점프하는 것이 가능합니다. 그리고 이러한 상황을 피하더라도 다른 코드가 스레드로 이동하여 TLS의 정보를 방해할 수 있습니다.
새 버전의 .NET에서는 이 문제를 해결하기 위해 ALS(비동기 로컬 저장소) 메커니즘을 도입했습니다. ALS는 의미상 스레드 로컬 저장소와 동일하지만 대기 호출을 통해 해당 점프를 수행할 수 있습니다. 이 함수는 내부적으로 CallContext 개체를 호출하여 데이터를 저장하는 AsyncLocal 일반 클래스를 통해 구현됩니다.
위 내용은 .NET의 성능 향상에 대한 자세한 살펴보기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!