[c#] C #에서 “in”매개 변수 수정자를 사용하는 이유는 무엇입니까?

그래서 나는 in매개 변수 수정자가 하는 일을 이해합니다 . 그러나 그것이하는 일은 상당히 중복되는 것처럼 보입니다.

일반적으로 a를 사용하는 유일한 이유 refin. 따라서 in참조로 전달하는 것은 논리적으로 값으로 전달하는 것과 같습니다.

성능상의 이점이 있습니까? 사물의 백엔드 측면에서 ref매개 변수는 최소한 변수의 물리적 주소를 복사해야하며, 이는 일반적인 객체 참조와 동일한 크기 여야한다는 것이 제 생각입니다.

그렇다면 더 큰 구조체에서만 이점이 있습니까, 아니면 다른 곳에서 매력적으로 만드는 몇 가지이면 컴파일러 최적화가 있습니까? 후자의 경우 왜 모든 매개 변수를 지정 하지 않아야 in합니까?



답변

in 최근에 C # 언어에 도입되었습니다.

in실제로 ref readonly. 일반적으로 in도움이 될 수있는 사용 사례는 하나뿐입니다 readonly struct. 많은 큰 s를 처리하는 고성능 앱 입니다.

다음이 있다고 가정합니다.

readonly struct VeryLarge
{
    public readonly long Value1;
    public readonly long Value2;

    public long Compute() { }
    // etc
}

void Process(in VeryLarge value) { }

이 경우 메서드 VeryLarge에서이 구조체를 Process사용할 때 (예 :를 호출 할 때 value.Compute()) 방어적인 복사본을 만들지 않고 구조체가 참조에 의해 전달되고 컴파일러가 구조체 불변성을 보장합니다.

수정 자 struct와 함께 읽기 전용이 아닌 것을 전달 in하면 컴파일러가 구조체의 메서드를 호출하고 위 메서드의 속성에 액세스 할 때 방어적인 복사본생성하여Process 성능에 부정적인 영향을 미칩니다!

주의 깊게 읽을 것을 권장 하는 정말 좋은 MSDN 블로그 항목 이 있습니다.

in-introducing에 대한 더 많은 역사적 배경을 알고 싶다면 C # 언어의 GitHub 저장소 에서이 토론 을 읽을 수 있습니다.

일반적으로 대부분의 개발자는 도입이 in실수로 보일 수 있다는 데 동의합니다 . 다소 이국적인 언어 기능이며 고성능 에지 경우에만 유용 할 수 있습니다.


답변

in참조로 전달하는 것은 논리적으로 값으로 전달하는 것과 같습니다.

옳은.

성능상의 이점이 있습니까?

예.

사물의 백엔드 측면에서 ref매개 변수는 최소한 변수의 물리적 주소를 복사해야하며, 이는 일반적인 객체 참조와 동일한 크기 여야한다는 것이 제 생각입니다.

없다 요구 사항은 그 변수에 개체에 대한 참조와 참조 모두 같은 크기로, 그리고 거기에없는 요구 사항 중 하나는 컴퓨터 워드의 크기는 것을,하지만 네, 실제로는 32에서 32 비트입니다 비트 머신 및 64 비트 머신의 64 비트.

“물리적 주소”가 그것과 관련이 있다고 생각하는 것은 저에게 분명하지 않습니다. Windows 에서는 사용자 모드 코드의 실제 주소 가 아닌 가상 주소 를 사용합니다. 어떤 상황에서 실제 주소가 C # 프로그램에서 의미가 있다고 상상할 수 있는지 궁금합니다.

또한 모든 종류의 참조를 스토리지의 가상 주소로 구현할 필요 도 없습니다 . 참조는 CLI 사양을 준수하는 구현에서 GC 테이블에 대한 불투명 한 핸들 일 수 있습니다.

더 큰 구조체에서만 장점이 있습니까?

더 큰 구조체를 전달하는 비용을 줄이는 것이 기능에 대한 동기 부여 시나리오 입니다.

in어떤 프로그램을 실제로 더 빠르게 만든다는 보장은 없으며 프로그램을 느리게 만들 수 있습니다. 성능에 대한 모든 질문은 경험적 연구를 통해 답해야합니다 . 항상이기는 최적화는 거의 없습니다 . 이것은 “항상 승리”최적화가 아닙니다.

다른 곳에서 매력적으로 만드는 비하인드 씬 컴파일러 최적화가 있습니까?

런타임 컴파일러 및된다 허용 하고 그렇게는 C # 사양의 규칙을 위반하지 않는 경우 그들이 선택하는 어떤 최적화를 할 수 있습니다. 내가 아는 한 in매개 변수에 대한 최적화는 아직 없지만 이것이 향후 이러한 최적화를 배제하지는 않습니다.

모든 매개 변수를 입력하지 않는 이유는 무엇입니까?

글쎄, 당신이 int매개 변수 대신 매개 변수 를 만들었다 고 가정하자 in int. 어떤 비용이 부과됩니까?

  • 이제 호출 사이트 에 값이 아닌 변수 가 필요합니다.
  • 변수를 등록 할 수 없습니다. 지터의 신중하게 조정 된 레지스터 할당 체계에 렌치가 들어 있습니다.
  • 호출 사이트의 코드는 변수에 대한 참조를 가져와 스택에 넣어야하기 때문에 더 큽니다. 반면에 단순히 값을 호출 스택에 푸시 할 수 있기 전에
  • 더 큰 코드는 일부 짧은 점프 명령이 이제 긴 점프 명령이 될 수 있음을 의미하므로 코드가 이제 더 커졌습니다. 이것은 모든 종류의 일에 영향을 미칩니다. 캐시는 더 빨리 채워지고, 지터는 더 많은 작업을 수행하고, 지터는 더 큰 코드 크기에 대해 특정 최적화를 수행하지 않도록 선택할 수 있습니다.
  • 피 호출자 사이트에서 스택 (또는 레지스터)의 값에 대한 액세스를 포인터로의 간접 지정으로 전환했습니다. 이제 포인터가 캐시에있을 가능성이 높지만 여전히 값에 대한 단일 명령어 액세스를 두 명령어 액세스로 전환했습니다.
  • 등등.

a라고 가정 double하고 in double. 다시 말하지만, 이제 변수는 고성능 부동 소수점 레지스터에 등록 될 수 없습니다. 이것은 성능에 영향을 미칠 뿐만 아니라 프로그램 동작을 변경할 수도 있습니다! C #은 64 비트 이상의 정밀도로 부동 산술을 수행 할 수 있으며 일반적으로 부동 소수점을 등록 할 수있는 경우에만 수행합니다.

이것은 무료 최적화가 아닙니다. 대안에 대한 성능을 측정해야합니다. 가장 좋은 방법은 디자인 지침에서 제안하는 것처럼 애초에 큰 구조체를 만들지 않는 것입니다.


답변

있습니다. 를 통과 할 때 structin키워드는 컴파일러는, 포인터를 전달해야하는 최적화 할 수 있습니다 내용을 변경하는 방법의 위험없이합니다. 마지막은 중요합니다. 복사 작업을 방지합니다. 큰 구조체에서 이것은 차이의 세계를 만들 수 있습니다.


답변

이것은 함수형 프로그래밍 접근 방식 때문에 수행됩니다. 주요 원칙 중 하나는 함수에 부작용이 없어야한다는 것입니다. 즉, 매개 변수 값을 변경해서는 안되며 일부 값을 반환해야합니다. C #에서는 값 변경을 허용하는 참조로만 복사하지 않고 구조체 (및 값 유형)를 전달할 방법이 없었습니다. 신속하게 메소드가 값을 변경하기 시작하는 한 구조체를 복사하는 해킹 알고리즘이 있습니다 (그들의 컬렉션은 구조체 BTW입니다). swift를 사용하는 사람들은 모두 복사 내용을 알지 못합니다. 이것은 메모리 효율적이고 명시 적이기 때문에 멋진 C # 기능입니다. 새로운 소식을 보면스택의 구조체와 배열에서 점점 더 많은 작업이 수행되는 것을 볼 수 있습니다. 그리고 진술은 이러한 기능에 필요합니다. 다른 답변에 언급 된 제한 사항이 있지만 .net이 어디로 향하고 있는지 이해하는 데 필수적인 것은 아닙니다.


답변

에서 그것의 C # 7.2 읽기 전용 기준은

이것은 구조에 대한 참조 만 전달 하는 ref 케이스 와 유사한 함수 스택에 전체 객체를 전달하지 않음을 의미합니다.

그러나 객체의 값을 변경하려고하면 컴파일러 오류가 발생합니다.

그리고 예, 큰 구조를 사용하는 경우 코드 성능을 최적화 할 수 있습니다.


답변