컴퓨터 과학에서 C ++ 표현식 템플릿을 언제 사용해야합니까? 언제 사용하지 않아야합니까?


24

C ++로 과학 코드를 작성한다고 가정 해 봅시다. 최근 동료와의 토론에서 표현 템플릿은 정말 나쁜 것일 수 있으며 특정 버전의 gcc에서만 소프트웨어를 컴파일 할 수 있다고 주장했습니다. 아마도이 문제는 이 몰락 패러디의 자막에서 암시 된 것처럼 몇 가지 과학적 코드에 영향을 미쳤습니다 . (이것들은 내가 아는 유일한 예이므로 링크입니다.)

그러나 다른 사람들은 SIAM Journal of Scientific Computing 의이 백서 에서처럼 임시 템플릿 에 중간 결과가 저장되는 것을 피함으로써 성능 향상을 가져올 수 있기 때문에 표현식 템플릿이 유용하다고 주장했습니다 .

C ++에서 템플릿 메타 프로그래밍에 대해 많이 알지 못하지만 자동 차별화 및 간격 산술에 사용되는 방법 중 하나라는 것을 알고 있습니다. 이는 표현식 템플릿에 대한 토론에 사용 된 방법입니다. 성능의 잠재적 이점과 유지 관리의 잠재적 단점 (올바른 단어 인 경우)을 모두 고려할 때 계산 과학에서 C ++ 표현식 템플릿을 사용해야하는 시점과이를 피해야하는 시점은 언제입니까?


아, 비디오가 너무 재밌다. 나는 그것이 존재하는지 몰랐다. 누가 만들 었는지 알아?
Wolfgang Bangerth

몰라; 두 명의 PETSc 사람들이 한 지점에서 링크를 보냈습니다. FEniCS 개발자가 만든 것 같습니다.
Geoff Oxberry

비디오 링크가 끊어지고 호기심으로 죽어 가고 있습니다. 새로운 링크?
Praxeolitic

어차피, 히틀러 비디오를 위해 유튜브 가 온 것을 본다 .
Praxeolitic

답변:


17

표현식 템플릿에 대한 나의 문제는 그것들이 매우 누출 된 추상화라는 것입니다. 더 복잡한 구문을 사용하여 간단한 작업을 수행하기 위해 매우 복잡한 코드를 작성하는 데 많은 작업을하게됩니다. 그러나 알고리즘을 변경하려면 더티 코드를 엉망으로 만들어야하고 유형이나 구문에 익숙하지 않으면 완전히 이해할 수없는 오류 메시지가 나타납니다. 응용 프로그램이 식 템플릿을 기반으로 라이브러리에 완벽하게 매핑되면 고려해 볼 가치가 있지만 확실하지 않은 경우 일반 코드를 작성하는 것이 좋습니다. 물론, 높은 수준의 코드는 예쁘지 않지만 필요한 작업을 수행 할 수 있습니다. 이점으로 컴파일 시간과 이진 크기가 줄어들고 컴파일러 및 컴파일 플래그 선택으로 인한 성능의 큰 차이에 대처할 필요가 없습니다.


예, gcc 2.95에서 gcc 4.x로 코드를 포팅해야 할 때 긴 오류 메시지를 직접 보았습니다. 컴파일러는 템플릿에 대한 모든 종류의 오류를 던졌습니다. 내 실험실 동료는 C ++에서 간격 산술을위한 템플릿 라이브러리를 개발 중입니다 (추가 연구를 수행하기 위해 Boost : : Interval에없는 새로운 기능 추가). 코드가 악몽이되는 것을보고 싶지 않습니다. 컴파일하기.
Geoff Oxberry

12

다른 사람들은 ET 프로그램을 작성하는 것이 얼마나 어려운 문제와 오류 메시지 이해의 복잡성에 대해 언급했습니다. 컴파일러 문제에 대해 언급하겠습니다. 큰 문제 중 하나는 모든 것이 작동하고 이식 가능하게 작동하도록 C ++ 표준을 충분히 준수하는 컴파일러를 찾는 것이 사실입니다. 그 결과, gcc, Intel icc, IBM xlC 및 Portland의 pgicc에 배포 된 2300 개의 버그 보고서가 있습니다. 따라서 deal.II 구성 스크립트는 주로 템플릿, 친구 선언, 네임 스페이스 등의 영역에서 많은 컴파일러 버그 테스트의 저장소입니다.

그러나 컴파일러 제조업체는 실제로 함께 행동했습니다. 오늘날 gcc와 icc는 오늘날 모든 테스트를 통과했으며 두 코드 사이에서 이식 가능한 코드를 작성하기 쉽습니다. 나는 PGI가 그리 멀지 않다고 말하지만 몇 년 동안 사라지지 않는 많은 단점이 있습니다. 반면에 xlC는 완전히 다른 이야기입니다. 6 개월마다 버그를 수정하지만 몇 년 동안 버그 보고서를 제출하더라도 진행 상황이 매우 느리고 xlC는 거래를 컴파일 할 수 없었습니다 .II.

이것이 의미하는 바는 다음과 같습니다. 두 개의 큰 컴파일러를 고수하면 오늘 작동 할 것으로 기대할 수 있습니다. 오늘날 대부분의 컴퓨터와 OS에는 일반적으로 그 중 하나 이상이 있으므로 충분합니다. 상황이 더 어려운 유일한 플랫폼은 시스템 컴파일러가 일반적으로 xlC이며 모든 버그가있는 BlueGene입니다.


호기심 때문에 / Q에서 새로운 xlc 컴파일러에 대해 컴파일을 시도 했습니까?
Aron Ahmadia

아니요. xlC를 포기했음을 인정합니다.
Wolfgang Bangerth

5

필자가 언급했듯이 컴파일러가 여전히 어려움을 겪고있는 오래 전 ET를 약간 실험했습니다. 나는 내 코드에서 선형 대수를 위해 블리츠 라이브러리를 사용했습니다 . 문제는 좋은 컴파일러를 얻었고 컴파일러 오류 메시지를 해석하는 완벽한 C ++ 프로그래머가 아니기 때문입니다. 후자는 단순히 관리 할 수 ​​없었습니다. 컴파일러는 평균적으로 약 1000 줄의 오류 메시지를 생성합니다. 프로그래밍 오류를 빨리 찾을 수 없었습니다.

우누 메릭스 웹 페이지 에서 더 많은 정보를 찾을 수 있습니다 (두 개의 ET 워크샵 진행 중).

그러나 나는 그들과 멀리 떨어져있을 것입니다 ....


컴파일러 오류 메시지는 실제로 내 관심사 중 하나입니다. 프로젝트를위한 라이브러리를 구축하기 위해 컴파일 된 템플릿 화 된 C ++ 코드 중 일부를 사용하면 컴파일러에서 수백 줄의 경고 메시지를 생성 할 수 있습니다. 그러나 그것은 내 코드가 아니며 이해하지 못하며 일반적으로 말하면 작동하므로 혼자 두십시오. 길고 암호 오류 메시지는 디버깅에 적합하지 않습니다.
Geoff Oxberry

4

문제는 이미 '식 템플릿 (ET)'이라는 용어로 시작됩니다. 그것에 대한 정확한 정의가 있는지 모르겠습니다. 그러나 일반적인 사용법에서 어떻게 '선형 대수 표현식을 코딩하는 방법'과 '계산 방법'을 결합합니다. 예를 들면 다음과 같습니다.

당신은 벡터 연산을 코딩

v = 2*x + 3*y + 4*z;                    // (1)

그리고 그것은 루프에 의해 계산됩니다.

for (int i=0; i<n; ++i)                 // (2)
    v(i) = 2*x(i) + 3*y(i) + 4*z(i);

내 생각에 이것은 두 가지 다른 점이며 분리되어야합니다 : (1) 인터페이스이고 (2) 하나의 가능한 구현. 이것이 프로그래밍에서 일반적인 관행임을 의미합니다. 물론 (2)는 좋은 기본 구현 일 수 있지만 일반적으로 전문화 된 전용 구현을 사용할 수 있기를 원합니다. 예를 들어, 나는 같은 기능을 원한다.

myGreatVecSum(alpha, x, beta, y, gamma, z, result);    // (3)

코딩 할 때 호출됩니다 (1). 아마도 (3)은 (2)와 같이 내부적으로 루프를 사용합니다. 그러나 벡터 크기에 따라 다른 구현이 더 효율적일 수 있습니다. 어쨌든 일부 고성능 전문가는 가능한 한 많이 구현하고 조정할 수 있습니다 (3). 따라서 (1)을 (3)의 호출에 매핑 할 수 없으면 (1)의 구문 설탕을 피하고 (3)을 직접 호출하십시오.

내가 설명하는 것은 새로운 것이 아닙니다. 반대로 BLAS / LPACK의 기본 개념은 다음과 같습니다.

  • LAPACK의 모든 성능 결정 작업은 BLAS 함수를 호출하여 수행됩니다.
  • BLAS는 일반적으로 필요한 선형 대수 표현식에 대한 인터페이스를 정의합니다.
  • BLAS의 경우 서로 다른 최적화 된 구현이 존재합니다.

BLAS의 범위가 충분하지 않은 경우 (예 : (3)과 같은 기능을 제공하지 않는 경우) BLAS의 범위를 확장 할 수 있습니다. 60 년대와 70 년대의이 공룡은 석기 시대 도구를 사용하여 인터페이스와 구현의 깨끗하고 직교적인 분리를 실현합니다. (대부분의) 숫자 C ++ 라이브러리가 이러한 수준의 소프트웨어 품질을 달성하지 못한다는 것은 재미 있습니다. 프로그래밍 언어 자체가 훨씬 더 정교하지만. 따라서 BLAS / LAPACK이 여전히 살아 있고 활발하게 개발되어 있다는 것은 놀라운 일이 아닙니다.

따라서 제 생각에 ET는 그 자체로 악이 아닙니다. 그러나 수치 C ++ 라이브러리에서 일반적으로 사용되는 방식은 과학 컴퓨팅 분야에서 매우 나쁜 평판을 얻었습니다.


마이클, 나는 당신이 표현 템플릿의 요점 중 하나를 놓치고 있다고 생각합니다. 코드 예제 (1)은 실제로 최적화 된 BLAS 호출에 매핑되지 않습니다. 실제로 BLAS 루틴이 존재하더라도 BLAS 함수 호출의 오버 헤드는 작은 벡터 및 행렬에 대해 상당히 끔찍합니다. Blaze 및 Eigen과 같은 정교한 표현식 템플릿 라이브러리는 임시 표현식의 사용을 피하기 위해 지연된 표현식 평가를 사용할 수 있지만, 도메인 특정 언어가 부족한 것은 거의 수동 롤 선형 대수를 이길 수 없다고 확신합니다.
Aron Ahmadia

아니요, 요점을 놓치고 있다고 생각합니다. : 당신은 몇 가지 자주 대수 동작 (B) 등이 FLENS에서 작동하는 방법 BTW 그 ATLAS 같은 BLAS, GotoBLAS의 구현 선형 필요로하는 사양의 (a) BLAS를 구별 할 필요가 기본적으로 식을 같이 (1)는 것 BLAS에서 axpy를 세 번 호출하여 평가됩니다. 그러나 (1)을 수정하지 않고 (2)와 같이 평가할 수도 있습니다. 따라서 논리적으로 발생하는 일은 다음과 같습니다. (1)과 같은 작업이 중요한 경우 지정된 BLAS 작업 집합 (a)을 확장 할 수 있습니다.
Michael Lehn

요점은 'v = x + y + z'와 같은 표기법과 최종 계산 방법을 분리해야한다는 것입니다. 이 점에서 Eigen, MTL, BLITZ, blaze-lib는 완전히 실패합니다.
Michael Lehn

1
그렇습니다. 그러나 자주 필요한 선형 대수 연산의 수는 조합 적입니다. C ++과 같은 언어를 사용하려는 경우 지연된 평가를 사용하여 하위 블록과 알고리즘을 지능적으로 결합하거나 대규모로 구현하여 식 템플릿을 사용하여 필요에 따라 구현 (이는 고유 / 블레이즈 방식)을 선택할 수 있습니다. 가능한 모든 루틴의 라이브러리. Numba와 Cython의 최근 연구에서 Python과 같은 고급 스크립팅 언어에서 비슷하거나 더 나은 성능을 얻을 수 있음을 보여 주므로 두 가지 접근 방식을 옹호하지 않습니다.
Aron Ahmadia

그러나 다시, 내가 불평하는 것은 아이겐과 같은 정교한 (복잡하지만 융통성없는 의미의) 라이브러리는 표기법과 평가 메커니즘을 밀접하게 결합하고 심지어 그것이 좋은 것이라고 생각한다는 사실입니다. Matlab과 같은 도구를 사용하는 경우 코드를 작성하고 Matlab이 최선을 다하고 있다는 것을 의지하고 싶습니다. C ++과 같은 언어를 사용하면 통제력을 갖기를 원합니다. 따라서 기본 평가 메커니즘이 존재하지만 변경할 수 있어야합니다. 그렇지 않으면 돌아가서 C ++에서 함수를 직접 호출합니다.
Michael Lehn 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.