이 글은 기계 번역의 미러 문서이며, 원본 기사로 바로 이동하려면 여기를 클릭해 주세요.

보기: 6317|회답: 3

[출처] [돌기]. NET 성능 최적화 - 리스트 컬렉션을 빠르게 탐색

[링크 복사]
2022-8-28 20:51:16에 게시됨 | | | |
간략한 소개

System.Collections.Generic.List<T>는 .NET의 일반적인 컬렉션 클래스로, 편리함과 풍부한 API 덕분에 모든 종류의 데이터를 저장할 수 있으며, 일상생활에서 널리 사용되고 가장 많이 사용되는 컬렉션 클래스라고 할 수 있습니다.

코드 작성에서는 종종 비즈니스 처리를 위해 리스트 컬렉션을 반복해서 통과<T>해야 합니다. 보통 세트 내에 많은 요소가 없고, 이동이 매우 빠릅니다. 하지만 빅데이터 처리, 통계, 실시간 컴퓨팅 등에서는 <T>수만 또는 수십만 개의 데이터 목록을 어떻게 빠르게 탐색할 수 있을까요? 오늘 여러분께 꼭 말씀드리고 싶은 게 바로 그 점입니다.

이동 모드

서로 다른 이동 방법의 성능을 살펴보고, 다음 성능 벤치마크를 만들어 보겠습니다. 다양한 크기 수집 탐색을 사용하여 다양한 방법들의 성능을 살펴보죠. 코드 스니펫은 다음과 같습니다:

foreach 문장을 사용하세요

foreach는 컬렉션을 탐색하는 가장 일반적인 방법이며, iterator 패턴의 구문 슈가 구현이고, 이 기간의 벤치마크로도 사용됩니다.

foreach 문이 구문 슈가이기 때문에, 컴파일러는 결국 GetEnumerator()와 MoveNext()를 while 루프로 호출하여 이 기능을 구현합니다. 컴파일된 코드는 다음과 같습니다:



MoveNext() 메서드 구현은 반복 중에 다른 스레드가 컬렉션을 수정하지 않도록 보장하며, 수정이 발생하면 InvalidOperationException 예외를 던지고, 현재 인덱스가 정당한지 확인하는 오버플로우 검사를 하며, 해당 요소를 열거자에게 할당해야 합니다. 현재 속성,그래서 실제로 성능이 최고는 아닙니다, 코드 스니펫은 다음과 같습니다:



다양한 세트 크기에서 어떻게 작동하는지 살펴보면, 결과는 다음과 같습니다:



크기가 다른 경우, 100w의 데이터를 처리 로치 없이 통과하더라도 최소 1초가 걸리는 시간 소모 과정의 선형 성장 관계가 필요하다는 것을 알 수 있습니다.

ForEach 메서드 리스트 사용

또 다른 일반적인 방법은 List를 사용하는 <T>것입니다. ForEach() 메서드는 Action delegate를 전달할 수 있게 해<T>주며, 이 메서드는 Action delegate가 요소를 반복할 때 호출합니다<T>.

<T>List의 내부 구현 방법으로서 개인 배열에 직접 접근하고 오버플로우 검사를 피할 수 있습니다. 이론적으로는 빠를 수 있어야 합니다; 하지만 우리 시나리오에서는 빈 메서드가 하나뿐이며, 완전 인라인 호출 foreach 메서드와 잘 맞지 않을 수 있습니다. 아래는 ForEach 메서드의 소스 코드로, 오버플로우 검사는 없지만 동시 버전 번호 검사는 유지합니다.



또한, 호출 코드에서 ForEach 메서드에 delegate를 전달해야 하므로 클로저 생성 클래스의 delegate 객체가 비어 있는지 매번 확인하고, 그렇지 않으면 아래 참조와 같이 새로운 Action()을 확인합니다<T>:



성능 면에서 foreach 키워드와 비교해 보겠습니다. 다음 이미지는 벤치마크 결과를 보여줍니다:



테스트 결과를 보면 foreach 키워드를 직접 사용하는 것보다 40% 느립니다. 필요하지 않다면 foreach 키워드를 직접 사용하는 것이 더 나은 선택인 것 같은데, 더 빠른 방법이 있을까요?

루프 탐색에 대해

가장 오래된 방법인 for 키워드를 사용해 컬렉션을 탐색하는 방법으로 돌아가 보겠습니다. 현재 이 방법이 가장 성능이 좋은 트래버설 방법일 것입니다. 이전 방식들처럼 중복 코드가 필요 없고(인덱서도 오버플로우 방지를 위해 점검됩니다), 버전 번호도 확인하지 않기 때문에 멀티스레드 환경에서는 컬렉션이 변경되고, for를 사용할 때 예외가 발생하지 않습니다. 테스트 코드는 다음과 같습니다:

결과가 어떻게 될지 지켜보자.



이것이 우리가 예상하는 방식인 것 같습니다.for를 직접 사용하는 것보다 forloop를 60% 빠릅니다, 이전에는 1초가 걸리던 세트가 이제는 400밀리초에 걸립니다. 그럼 더 빠른 방법이 있을까요?

CollectionsMarshal 사용

.NET5 이후, 닷넷 커뮤니티는 수집 작업 성능을 향상시키기 위해 CollectionsMarshal 클래스를 구현했습니다. 이 클래스는 컬렉션 타입의 네이티브 배열에 접근하는 방법을 구현합니다 (제 [. .NET 성능 최적화 - 컬렉션 타입의 초기 크기를 설정해야 합니다] 문서, 많은 데이터 구조의 기본 구현이 배열이라는 것을 알고 계시죠. 그래서 모든 종류의 감지를 건너뛰고 원래 배열에 직접 접근할 수 있는데, 그게 가장 빠를 겁니다. 코드는 다음과 같습니다:

컴파일러가 생성하는 코드가 매우 효율적임을 알 수 있습니다.



기본 배열에 직접 접근하는 것은 매우 위험하며, 각 코드 줄을 어떻게 처리하는지 알고 충분한 테스트를 해야 합니다. 벤치마크 결과는 다음과 같습니다:



와우CollectionsMarshal을 사용하는 것이 foreach보다 79% 빠릅니다하지만 이것이 JIT 최적화의 이유여야 하며, foreach와 for keyword loop Span을 사용하는 것 사이에 큰 차이는 없습니다.

요약

오늘은 리스트 컬렉션을 빠르게 탐색하는 방법에 대해 이야기했는데, 대부분의 경우 오버플로우 검사와 다중 스레드 버전 번호 제어가 포함된 foreach 키워드를 사용하는 것이 권장되어, 올바른 코드를 작성하기를 더 쉽게 해줍니다.

고성능과 대용량 데이터 볼륨이 필요하다면, 컬렉션을 직접 탐색하기 위해 CollectionsMarshal.AsSpan을 사용하는 것이 권장됩니다.

이 기사의 출처 코드 링크:

하이퍼링크 로그인이 보입니다.

원본 링크:하이퍼링크 로그인이 보입니다.





이전의:RabbitMQ AMQP 메시지 아키텍처에 대한 상세 설명
다음:네트워크 케이블 크리스털 헤드 T568A 및 T568B 표준 및 차이점
2022-9-4 22:15:52에 게시됨 |
배우기 위해 배우세요
2022-9-8 10:33:05에 게시됨 |
배우기 위해 배우세요
2023-6-27 22:39:13에 게시됨 |
안녕하세요 12306, 데이터가 포함된 개인 메시지 보내주실 수 있나요?
면책 조항:
Code Farmer Network에서 발행하는 모든 소프트웨어, 프로그래밍 자료 또는 기사는 학습 및 연구 목적으로만 사용됩니다; 위 내용은 상업적 또는 불법적인 목적으로 사용되지 않으며, 그렇지 않으면 모든 책임이 사용자에게 부담됩니다. 이 사이트의 정보는 인터넷에서 가져온 것이며, 저작권 분쟁은 이 사이트와는 관련이 없습니다. 위 내용은 다운로드 후 24시간 이내에 컴퓨터에서 완전히 삭제해야 합니다. 프로그램이 마음에 드신다면, 진짜 소프트웨어를 지원하고, 등록을 구매하며, 더 나은 진짜 서비스를 받아주세요. 침해가 있을 경우 이메일로 연락해 주시기 바랍니다.

Mail To:help@itsvse.com