문제

나는 종종 Perl에서 어떤 정보로 배열을 채우는 서브루틴을 가지고 있습니다.나는 또한 C++ 해킹에 익숙하기 때문에 Perl에서 참조를 사용하여 다음과 같은 작업을 수행하는 경우가 많습니다.

my @array;
getInfo(\@array);

sub getInfo {
   my ($arrayRef) = @_;
   push @$arrayRef, "obama";
   # ...
}

보다 간단한 버전 대신:

my @array = getInfo();

sub getInfo {
   my @array;
   push @array, "obama";
   # ...
   return @array;
}

물론 그 이유는 배열이 서브루틴에서 로컬로 생성된 다음 반환 시 복사되는 것을 원하지 않기 때문입니다.

그렇죠?아니면 Perl은 어쨌든 그것을 최적화합니까?

도움이 되었습니까?

해결책

처음에 배열 참조를 반환하는 것은 어떻습니까?

sub getInfo {
  my $array_ref = [];
  push @$array_ref, 'foo';
  # ...
  return $array_ref;
}

my $a_ref = getInfo();
# or if you want the array expanded
my @array = @{getInfo()};

Dehmann의 의견에 따라 편집 :

함수에서 일반 배열을 사용하고 참조를 반환 할 수도 있습니다.

sub getInfo {
  my @array;
  push @array, 'foo';
  # ...
  return \@array;
}      

다른 팁

통과 참조가 더 효율적이지만 차이는 C ++만큼 크지 않습니다. 인수 값 자체 (즉, 배열의 값)는 항상 참조로 전달됩니다 (반환 된 값은 복사됩니다).

질문은 : 중요합니까? 대부분의 경우에는 그렇지 않습니다. 5 개의 요소를 반환하고 있다면 귀찮게하지 마십시오. 100'000 요소를 반환/통과하는 경우 참조를 사용하십시오. 병목 현상 인 경우에만 최적화하십시오.

내가 당신의 예를보고 당신이하고 싶은 일에 대해 생각하면 나는 이런 식으로 그것을 쓰는 데 익숙합니다.

sub getInfo {
  my @array;
  push @array, 'obama';
  # ...
  return \@array;
}

그것은 나에게 보인다 간단한 버전 많은 양의 데이터를 반환해야 할 때. 필요하지 않습니다 할당 외부 배열 sub 첫 번째 코드 스 니펫에 작성된대로 my 당신을 위해 그것을하십시오. 어쨌든 당신은 조기 최적화를하지 않아야합니다 레온 티머 맨 제안하다.

최종 반추에 응답하기 위해 Perl은 이것을 최적화하지 않습니다. 배열을 반환하고 스칼라를 반환하는 것은 근본적으로 다르기 때문에 실제로는 할 수 없습니다.

많은 양의 데이터를 다루거나 성능이 큰 문제인 경우 C 습관이 잘 제공됩니다. 구조 자체가 아닌 데이터 구조에 대한 참조를 통과하고 반환하여 복사 할 필요가 없습니다. 그러나 Leon Timmermans가 지적했듯이, 대부분의 시간은 소수의 데이터와 성능을 다루는 것이 그다지 큰 거래가 아니므로 가장 읽을 수있는 방법으로는 그다지 중요하지 않습니다.

이것이 제가 일반적으로 배열을 반환하는 방식입니다.

sub getInfo {
  my @array;
  push @array, 'foo';
  # ...
  return @array if wantarray;
  return \@array;
}

이렇게하면 원하는 방식으로, 스칼라 또는 목록 컨텍스트에서 작동합니다.

my $array = getInfo;
my @array = getInfo;

$array->[0] == $array[0];

# same length
@$array == @array;

코드의 느린 부분이라는 것을 알지 않는 한 최적화하려고하지 않을 것입니다. 그럼에도 불구하고 나는 벤치 마크를 사용하여 실제로 어떤 서브 루틴이 실제로 더 빠른지 확인할 것입니다.

두 가지 고려 사항이 있습니다. 명백한 것은 배열이 얼마나 큰지? 수십 개의 요소 미만인 경우 크기는 요인이 아닙니다 (빠르게 호출되는 기능을 미세 최적화하지 않는 한 먼저 메모리 프로파일 링을 수행해야합니다).

그것은 쉬운 부분입니다. 간과 된 두 번째 고려 사항은 인터페이스입니다. 반환 된 배열은 어떻게 사용됩니까? 전체 배열 Dereferencing이 Perl에서 끔찍하기 때문에 이것은 중요합니다. 예를 들어:

for my $info (@{ getInfo($some, $args) }) {
    ...
}

못 생겼어. 이것은 훨씬 낫습니다.

for my $info ( getInfo($some, $args) ) {
    ...
}

또한 매핑과 그레핑에 적합합니다.

my @info = grep { ... } getInfo($some, $args);

그러나 개별 요소를 선택하려면 배열 심판을 반환하는 것이 유용 할 수 있습니다.

my $address = getInfo($some, $args)->[2];

그것은 :보다 간단합니다.

my $address = (getInfo($some, $args))[2];

또는:

my @info = getInfo($some, $args);
my $address = $info[2];

그러나 그 시점에서 @info가 진정으로 목록인지 해시인지 의문을 제기해야합니다.

my $address = getInfo($some, $args)->{address};

당신이하지 말아야 할 것은 가지고 있습니다 getInfo() 스칼라 컨텍스트에서 배열 심판을 반환하고 목록 컨텍스트에서 배열을 반환합니다. 이것은 스칼라 컨텍스트의 전통적인 사용을 배열 길이로 사용하여 사용자를 놀라게합니다.

마지막으로, 나는 내 자신의 모듈을 꽂을 것입니다. 방법 :: 서명, 배열 참조 구문을 사용하지 않고 배열 참조를 전달하기위한 타협을 제공하기 때문입니다.

use Method::Signatures;

method foo(\@args) {
    print "@args";      # @args is not a copy
    push @args, 42;   # this alters the caller array
}

my @nums = (1,2,3);
Class->foo(\@nums);   # prints 1 2 3
print "@nums";        # prints 1 2 3 42

이것은 마법을 통해 이루어집니다 데이터 :: 별명.

전체 용량이 큰 파일을 읽고 이를 배열로 분할하는 경우 잠재적으로 큰 성능 향상이 가능한 3가지:

  1. read () 대신 sysread ()로 버퍼링을 끄십시오 (믹싱에 대한 수동 경고)
  2. 마지막 요소를 평가하여 배열을 사전 확장 - 메모리 할당을 저장합니다.
  3. Unpack()을 사용하여 uint16_t 그래픽 채널 데이터와 같은 데이터를 신속하게 분할합니다.

함수에 배열 참조를 전달하면 기본 프로그램이 간단한 배열을 처리할 수 있는 반면, 한 번 쓰고 잊어버리는 작업자 함수는 더 복잡한 "$@" 및 화살표 ->[$II] 액세스 형식을 사용합니다.꽤 C'ish이기 때문에 빠를 것 같습니다!

나는 Perl에 대해 아무것도 모른다. 그래서 이것은 언어 중립 대답이다.

어떤 의미에서, 서브 루틴에서 배열을 호출 프로그램으로 복사하는 것은 비효율적입니다. 비 효율성은 사용 된 추가 메모리와 한 장소에서 다른 장소로 데이터를 복사하는 데 걸리는 시간에 발생합니다. 반면에, 가장 큰 배열을 제외한 모든 배열을 제외한 모든 배열을 위해, 당신은 망할 수 없으며, 우아함, 욕심 또는 다른 이유를 위해 배열을 복사하는 것을 선호 할 수 있습니다.

효율적인 솔루션은 서브 루틴이 호출 프로그램을 배열의 주소를 통과시키는 것입니다. 내가 말했듯이, 나는이 점에서 Perl의 기본 행동에 대한 단서가 없었다. 그러나 일부 언어는 프로그래머에게 어떤 접근법을 선택할 수있는 옵션을 제공합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top