병렬 배열

Parallel array

컴퓨팅에서 병렬 배열 그룹(배열 구조 또는 SoA라고도 함)은 여러 배열을 사용하여 단일 레코드 배열을 나타내는 암묵적 데이터 구조의 한 형태입니다.레코드의 각 필드에 대해 각각 동일한 수의 요소를 가진 개별 동종 데이터 배열을 유지합니다.그런 다음 각 배열의 동일한 인덱스에 있는 개체는 암묵적으로 단일 레코드의 필드가 됩니다.개체 간에 포인터는 배열 인덱스로 대체됩니다.이는 각 레코드의 모든 필드를 메모리에 함께 저장하는 일반적인 접근 방식(구조 배열 또는 AoS라고도 함)과 대비됩니다.예를 들어 각각 100개의 이름(각 문자열)과 100개의 에이징(Age)으로 이루어진 배열을 선언하여 각 이름을 동일한 인덱스를 가진 에이징과 연관지을 수 있습니다.

병렬 어레이를 사용한 C의 예:

인트  한참[]   = {0,          17,        2,          52,         25};  *이름[] = {"없음",     '마이크,    "빌리,    "톰",      '스탠'}; 인트  부모[] = {0 /*없음*/, 3 /*Tom*/, 1 /*마이크*/, 0 /*없음*/, 3 /*Tom*/};  위해서 (i = 1; i <=> 4; i++) {     인쇄물("이름: %s, 연령: %d, 부모: %s\n",            이름[i], 한참[i], 이름[부모[i]]); } 

Perl의 경우(어레이의 해시를 사용하여 각 어레이에 대한 참조를 보유):

나의 %data = (     이름   => ['조',  ,  '프랭크',  한스    ],     성_이름    => ['스미스','세저',시나트라,'슐츠],     높이_in_cm => [169,     158,    201,      199      ]);  위해서 i달러 (0..$#{데이터{이름}}) {     인쇄물 "이름: %s %s\n", 데이터{이름}[i달러], 데이터{성_이름}[i달러];     인쇄물 "높이(CM): %i\n", 데이터{높이_in_cm}[i달러]; } 

또는 Python의 경우:

이름   = ['조',  ,  "프랭크",  "한스'    ] last_names    = ["스미스",'세저',시나트라,'슐츠"] 높이_in_cm = [169,     158,    201,      199      ]  위해서 i  범위((이름)):     인쇄물("이름:%s %s" % (이름[i], last_names[i]))     인쇄물("높이(cm):%s" % 높이_in_cm[i])  # zip 사용: 위해서 이름, 성_이름, 높이_in_cm  지퍼(이름, last_names, 높이_in_cm):     인쇄물(f"이름:{이름} {성_이름}")     인쇄물(f"높이(cm):{높이_in_cm}") 

장점과 단점

병렬 어레이에는 일반 접근 방식에 비해 다음과 같은 많은 실질적인 이점이 있습니다.

  • 얼라인먼트 문제를 회피함으로써 경우에 따라서는 상당한 공간을 절약할 수 있습니다.예를 들어, 일부 아키텍처는 4바이트 정수가 항상 4의 배수인 메모리 위치에 저장되어 있을 때 가장 잘 작동합니다.이전 필드가 1바이트일 경우 3바이트가 낭비될 수 있습니다.대부분의 최신 컴파일러는 자동으로 이러한 문제를 회피할 수 있지만, 과거에는 일부 프로그래머가 정렬 제한을 줄이는 순서로 필드를 명시적으로 선언했습니다.
  • 항목 수가 적은 경우, 특히 일부 아키텍처에서는 어레이 인덱스가 풀 포인터보다 훨씬 적은 공간을 차지할 수 있습니다.
  • 어레이 내의 각 레코드의 단일 필드를 순차적으로 검사하는 것은 단일 어레이의 선형 횡단에 해당하므로 최신 머신에서는 매우 빠릅니다. 이는 참조 및 캐시 동작의 이상적인 인접성을 나타냅니다.
  • 특정 명령 집합 아키텍처에서 SIMD 명령을 사용하여 효율적으로 처리할 수 있습니다.

이러한 이점 중 일부는 사용 중인 특정 프로그래밍 언어 및 구현에 크게 좌우됩니다.

그러나 병렬 어레이에는 다음과 같은 몇 가지 강력한 단점도 있습니다.이 단점은 이러한 단점이 일반적으로 선호되지 않는 이유를 설명해 줍니다.

  • 다양한 배열이 임의로 멀리 떨어져 저장될 수 있기 때문에 비순차적으로 레코드를 방문하여 각 레코드의 여러 필드를 조사할 때 참조 인접성이 현저히 떨어집니다.
  • 단일 레코드의 필드 간 관계를 모호하게 한다(예: 유형 정보가 서로 지수를 관련짓지 않고 지수를 잘못 사용할 수 있다).
  • 이러한 언어에는 직접적인 언어 지원이 거의 없습니다(일반적으로 언어와 그 구문은 병렬 배열 내의 어레이 간의 관계를 나타내지 않으며 오류를 검출할 수 없습니다).
  • 필드의 번들은 "물건"이 아니기 때문에, 그것을 이리저리 돌리는 것은 지루하고 오류가 발생하기 쉽습니다.예를 들어, 함수를 호출하여 하나의 레코드(또는 구조 또는 객체)에 작업을 수행하는 대신, 함수는 필드를 별도의 인수로 사용해야 합니다.새 필드가 추가 또는 변경되면 많은 매개 변수 목록을 변경해야 합니다. 여기서 개체 전체를 전달하면 이러한 변경이 완전히 방지됩니다.
  • 여러 어레이를 각각 재할당해야 하므로 확장 또는 축소하는 데 비용이 많이 듭니다.멀티 레벨 어레이는 이 문제를 개선할 수 있지만 원하는 요소를 찾기 위해 필요한 추가 방향 지정이 필요하기 때문에 성능에 영향을 미칩니다.
  • 아마도 가장 나쁜 것은 오류의 가능성을 크게 높인다는 것입니다.삽입, 삭제 또는 이동은 항상 모든 어레이에 일관되게 적용해야 합니다.그렇지 않으면 어레이가 서로 동기화되지 않아 비정상적인 결과를 초래할 수 있습니다.

참조의 부정한 인접성은 경우에 따라 완화될 수 있습니다.구조물을 일반적으로 함께 액세스되는 필드 그룹으로 분할할 수 있는 경우 각 그룹에 대해 배열을 구성할 수 있으며, 그 요소는 더 큰 구조체 필드의 이러한 하위 집합만 포함하는 레코드입니다.(데이터 지향 설계 참조).이는 구성원들이 많이 있는 매우 큰 구조물에 대한 접근을 가속화하고 구조물의 일부를 함께 묶는 데 유용한 방법입니다.어레이 인덱스를 사용하여 이들을 결합하는 다른 방법으로는 참조를 사용하여 부분을 결합하는 방법이 있지만, 이 방법은 시간과 공간의 효율성이 떨어질 수 있습니다.

또 다른 방법은 단일 배열을 사용하는 것입니다. 여기서 각 엔트리는 레코드 구조입니다.많은 언어가 실제 기록과 그 배열을 선언하는 방법을 제공합니다.다른 언어에서는 n*m 크기의 배열을 선언하여 시뮬레이트할 수 있습니다.여기서 m은 모든 필드의 크기를 나타냅니다.특정 언어가 레코드를 직접 지원하지 않더라도 효과적으로 레코드에 필드를 채웁니다.일부 컴파일러 최적화, 특히 벡터 프로세서는 프로그램에서 [citation needed]구조 배열이 생성될 때 이 변환을 자동으로 수행할 수 있습니다.

「 」를 참조해 주세요.

레퍼런스

  • 토마스 H. 코먼, 찰스 E. 리저슨, 로널드 L. 리베스트, 클리포드 스타인.알고리즘 소개, 제2판MIT Press and McGraw-Hill, 2001. ISBN0-262-03293-7.섹션 10.3 페이지 209: 포인터 및 객체 구현.
  • Skeet, Jon (3 June 2014). "Anti-pattern: parallel collections". Retrieved 28 October 2014.