[performance] Raku가 다차원 배열에서 왜 그렇게 성능이 좋지 않습니까?

Raku가 다차원 배열을 잘못 조작하는 이유가 궁금합니다. Python, C # 및 Raku에서 2 차원 행렬을 초기화하는 빠른 테스트를 수행했으며 경과 시간이 놀랍게도 나중에 높았습니다.

라쿠

my @grid[4000;4000] = [[0 xx 4000] xx 4000];
# Elapsed time 42 seconds !!

파이썬

table= [ [ 0 for i in range(4000) ] for j in range(4000) ]
# Elapsed time 0.51 seconds

씨#

int [,]matrix = new int[4000,4000];
//Just for mimic same behaviour
for(int i=0;i<4000;i++)
   for(int j=0;j<4000;j++)
       matrix[i,j] = 0;
# Elapsed time 0.096 seconds

내가 잘못하고 있습니까? 너무 큰 차이가있는 것 같습니다.



답변

초기 직접 비교

나는 자신의 번역보다 파이썬 코드와 훨씬 더 밀접한 코드로 시작할 것이다. 나는 생각 파이썬이에 가장 직접적으로 해당 년대 라쿠 코드를 :

my \table = [ [ 0 for ^4000 ] for ^4000 ];
say table[3999;3999]; # 0

이 코드는 무 증착 식별자 1을 선언합니다 . 그것:

  • “형성”을 삭제합니다 ( [4000;4000]에서 my @table[4000;4000]). 파이썬 코드가하지 않기 때문에 삭제했습니다. 형성은 장점을 제공하지만 성능에 영향을 미칩니다. 2

  • 용도 바인딩 대신 할당 . 파이썬 코드가 할당이 아닌 바인딩을하고 있기 때문에 바인딩으로 전환했습니다. (Python은이 둘을 구별하지 않습니다.) Raku의 할당 방식은 일반적인 코드에 필요한 기본적인 이점을 제공하지만 성능에 영향을 미칩니다.


내가 대답하기 시작한이 코드는 여전히 느립니다.

먼저 2018 년 12 월부터 Rakudo 컴파일러를 통해 실행되는 Raku 코드는 2019 년 6 월 Python 인터프리터를 사용하는 동일한 하드웨어에서 Python 코드보다 약 5 배 느립니다.

둘째, Raku 코드와 Python 코드는 모두 C # 코드와 비교할 때 느립니다. 우리는 더 잘할 수 있습니다 …

천 배 더 빠른 관용적 대안

다음 코드를 고려해 볼 가치가 있습니다.

my \table = [ [ 0 xx Inf ] xx Inf ];
say table[ 100_000; 100_000 ]; # 0

이 코드는 Python 및 C # 코드에서 1,600 만 개의 요소가 아닌 100 억 개의 요소 배열에 해당하지만 , 실행하는 데 걸리는 시간은 Python 코드의 절반보다 짧으며 C #보다 5 배 느립니다. 암호. 이는 Rakudo가 동등한 Python 코드보다 1000 배, C # 코드보다 100 배 빠른 Raku 코드를 실행하고 있음을 나타냅니다.

Raku 코드는를 사용하여 테이블이 느리게 초기화되기 때문에 훨씬 빠릅니다 xx Inf. 4say 라인 을 운영하는 데있어 중요한 작업은 유일 합니다. 이로 인해 첫 번째 1 차원 배열이 100,000 개 생성 된 다음 10 만 번째 2 차원 배열에 100,000 개의 요소가 채워 지므로 해당 배열의 마지막 요소에 보류를 say표시 할 수 있습니다 0.

여러 가지 방법이 있습니다

귀하의 질문에 대한 한 가지 문제는 항상 여러 가지 방법이 있다는 것입니다. 5 속도가 중요한 코드의 성능이 저하 된 경우 코드를 다르게 코딩하면 크게 달라집니다. 6

(또 다른 좋은 옵션은 SO 질문을하는 것입니다 …)

미래

라쿠 신중 매우 optimiz 수 있도록 설계되었습니다 , 즉 하루 실행 훨씬 빠르게 주어 향후 몇 년에 걸쳐 충분한 컴파일러 작업 그들이 접지 – 통과하지 않는 한, 3 캔, 이론적으로, 지금까지 실행, 말,보다, 펄 5, 파이썬 재 설계와 수년간의 해당 컴파일러 작업.

다소 괜찮은 비유는 지난 25 년 동안 Java의 성능으로 발생한 것입니다. Rakudo / NQP / MoarVM은 Java 스택이 거친 성숙 프로세스의 절반 정도입니다.

각주

1 나는 쓸 수 있었다 my $table := .... 그러나 형태의 선언은 my \foo ...sigils 고려를 제거하고 사용할 수있는 =것이 아니라 :=이는 sigil’d 식별자해야 할 것입니다. 보너스로 “시길을 슬래시 (slash out)”하면시길이없는 식별자가되는데, 물론 파이썬과 C #을 포함하는시길을 사용하지 않는 많은 언어의 코더들에게 친숙합니다.

2 언젠가 쉐이핑하면 일부 코드의 배열 작업이 더 빨라질 수 있습니다. 한편, 귀하의 질문에 대한 의견에서 언급했듯이, 현재 반대 방향으로 진행되어 크게 느려집니다. 모든 배열 액세스가 현재 순진하게 동적으로 경계 검사되고 모든 것이 느리게 진행되고 고정 크기를 사용하여 작업 속도를 높이는 노력이 없었기 때문에 이것이 큰 부분이라고 생각합니다. 또한 코드에 대한 빠른 해결 방법을 찾으려고 할 때 현재 고정 크기 배열에 대한 많은 작업이 현재 구현되지 않아 고정 크기 배열을 사용하는 것을 찾지 못했습니다. 다시 말하지만, 이것들은 언젠가 구현 될 것이지만 아마도 누군가가 지금까지 구현하기에 충분한 어려움이 아닐 것입니다.

3 이 글을 쓰는 시점에서 TIO 는 2019 년 6 월부터 Python 3.7.4를, 2018 년 12 월부터 Rakudo v2018.12를 사용하고 있습니다. Rakudo의 성능은 현재 공식 Python 3 인터프리터보다 시간이 지남에 따라 훨씬 빠르게 향상되고 있습니다. Rakudo가 느릴 때 최신 Rakudo와 최신 Python 사이의 간격 이이 답변에 명시된 것보다 훨씬 좁을 것으로 기대하십시오. 특히, 현재 작업은 과제 수행 능력을 크게 향상시키고 있습니다.

4는 xx 기본적으로 지연 처리로 설정되지만 일부 표현식은 언어 의미 또는 현재 컴파일러 제한으로 인해 평가를 강요합니다. 하여 세 v2018.12 Rakudo에서 양식의 표현에 대한 [ [ foo xx bar ] xx baz ]게으른 유지하고 간절히 평가하도록 강요 할 수 없습니다, 모두 bar 하고 baz있어야합니다 Inf. 반면, my \table = [0 xx 100_000 for ^100_000]전혀 사용과 게으른입니다 Inf. (후자의 코드는 실제로 10 만 개 저장하는 Seq대신 10 개보다 첫 번째 차원에들 Array-의 say WHAT table[0]표시 Seq가 아니라 Array– 그러나 대부분의 코드는 차이를 발견 할 수 없습니다 – say table[99_999;99_999]여전히 표시됩니다 0.)

(5) 일부 사람들은이 있다고 생각 약점 주어진 문제에 대한 코드 솔루션을 생각하는 하나 개 이상의 방법이 받아 들일 수 있습니다. 실제로 그것은 적어도 세 가지 측면에서 강점 입니다. 첫째, 일반적으로 주어진 사소한 문제는 성능 프로파일의 극적인 차이를 가진 많은 고유 한 알고리즘으로 해결할 수 있습니다. 이 답변에는 일부 시나리오에서 실제로 Python보다 천 배 이상 빠른 1 년 된 Rakudo에서 이미 사용 가능한 접근 방식이 포함됩니다. 둘째, Raku와 같이 고의적으로 유연하고 다중 패러다임 언어를 사용하면 코더 (또는 코더 팀)가 우아하고 유지 관리 가 가능 하다고 생각하거나 작업을 수행 할 수 있는 솔루션을 표현할 수 있습니다.언어가 강요하는 것이 아니라 최선이라고 생각하십시오. 셋째, 최적화 컴파일러로서의 Rakudo의 성능은 현재 가변적입니다. 다행히도 훌륭한 프로파일 러 6 을 가지고 있기 때문에 병목 현상의 위치와 유연성을 파악할 수 있으므로 대체 코딩을 시도하면 훨씬 빠른 코드를 생성 할 수 있습니다.

6 성능이 중요하거나 성능 문제를 조사하는 경우 성능에 관한 Raku 문서 페이지를 참조하십시오 . 이 페이지는 Rakudo 프로파일 러 사용을 포함한 다양한 옵션을 다룹니다.


답변