C #의 인라인 함수?


276

C #에서 "인라인 함수"를 어떻게 수행합니까? 나는 그 개념을 이해하지 못한다고 생각합니다. 그들은 익명의 방법을 좋아합니까? 람다 함수처럼?

참고 : 답변은 거의 대부분 함수 인라인 기능 , 즉 "함수 호출 사이트를 수신자의 본문으로 대체하는 수동 또는 컴파일러 최적화"를 처리합니다. 당신이에 관심이 있다면 익명 함수 (람다 일명) 을 참조 @ jalf의 답변 또는 어떤이 '람다'모두 계속 말하고입니다? .


11
마침내 가능합니다-내 대답을 참조하십시오.
konrad.kruczynski

1
.NET 4.5 이전의 가장 가까운 것은 변수를 람다 함수로 정의하는 방법 질문을 참조하십시오 . 실제로 인라인으로 컴파일되지는 않지만 인라인 선언과 같은 짧은 함수 선언입니다. 인라인을 사용하여 달성하려는 대상에 따라 다릅니다.
AppFzx 2016 년

답변:


384

마지막으로 .NET 4.5에서 CLR을 사용하면 값을 사용하여 1 개의 메소드 인라인 을 암시 / 제안 할 수 있습니다 MethodImplOptions.AggressiveInlining. 모노 트렁크 (오늘 커밋)에서도 사용할 수 있습니다.

// The full attribute usage is in mscorlib.dll,
// so should not need to include extra references
using System.Runtime.CompilerServices; 

...

[MethodImpl(MethodImplOptions.AggressiveInlining)]
void MyMethod(...)

1 . 이전에는 "힘"이 사용되었습니다. 몇 개의 downvotes가 있었으므로 용어를 명확히하려고 노력할 것입니다. 의견 및 문서에서와 같이, The method should be inlined if possible.특히 Mono (개방형)를 고려할 때 인라인 또는보다 일반적인 것 (가상 함수와 같은)을 고려할 때 일부 특정 기술적 제한이 있습니다. 전반적으로 그렇습니다. 이것은 컴파일러에 대한 힌트이지만, 그것이 요청 된 것 같습니다.


17
+1-프레임 워크 버전 요구 사항에 대해보다 구체적으로 답변을 업데이트했습니다.
M.Babcock

4
여전히 강제 인라인은 아니지만 대부분의 상황에서 JITters 휴리스틱을 재정의하는 것으로 충분합니다.
코드 InChaos

7
모든 .NET 버전에서 작동 할 수있는 다른 접근 방식은 약간 큰 메소드를 두 개의 메소드로 나누는 것입니다. 하나는 32 바이트의 IL을 초과하지 않는 다른 하나를 호출하는 것입니다. 순 효과는 원본이 인라인 된 것과 같습니다.
Rick Sladkey

4
"Inlining"을 강요하는 것이 아니라 단지 JIT와 대화하고 프로그래머가 실제로 Inlining을 사용하기를 원한다고 말하지만 JIT에는 마지막 단어가 있습니다. 따라서 MSDN : 가능한 경우 방법을 인라인해야합니다.
Orel Eraki

11
이에 비해 C ++의 인라인 제안, 심지어 컴파일러 관련 제안도 실제로 인라인을 강요하지는 않습니다. 모든 함수가 인라인 될 수있는 것은 아닙니다 (기본적으로 재귀 함수와 같은 것은 어렵지만 다른 경우도 있습니다). 그렇습니다.이 "quite"힘은 일반적입니다.
Eamon Nerbonne

87

인라인 메소드는 단순히 함수 코드가 호출자에게 롤링되는 컴파일러 최적화입니다.

C #에서는이 작업을 수행 할 수있는 메커니즘이 없으며 지원되는 언어로 드물게 사용되어야합니다. 어딘가에서 사용해야하는 이유를 모르는 경우 사용해서는 안됩니다.

편집 : 명확히하기 위해 두 가지 중요한 이유가 있습니다.

  1. 필요하지 않은 경우 인라인을 사용하여 대규모 바이너리를 쉽게 만들 수 있습니다.
  2. 컴파일러는 성능 관점에서 무언가 인라인되어야 할 때보 다 더 잘 알고 있습니다.

일을 내버려두고 컴파일러가 작업을 수행하도록 한 다음 인라인이 최상의 솔루션인지 프로파일 링하고 파악하는 것이 가장 좋습니다. 물론 일부는 인라인되는 것이 합리적이지만 (특히 수학 연산자) 컴파일러가 처리하도록하는 것이 일반적으로 모범 사례입니다.


35
일반적으로 컴파일러가 인라인을 처리하는 것이 좋습니다. 그러나 컴파일러 결정을 재정의하고 메소드를 인라인 또는 인라인하지 않는 상황이 있습니다.
mmmmmmmm 2012 년

7
@Joel Coehoorn : 모듈화 및 액세스 보호를 손상시킬 수 있으므로 이는 나쁜 습관입니다. (개인 멤버에 액세스하고 코드의 다른 지점에서 호출되는 클래스의 인라인 메소드에 대해 생각해보십시오!)
mmmmmmmm

9
@Poma 인라인을 사용해야하는 이상한 이유입니다. 나는 그것이 효과적 일 것이라고 의심한다.
Chris Shouts

56
가장 잘 아는 컴파일러에 대한 주장은 잘못되었습니다. 32 IL 바이트보다 큰 메소드는 인라인하지 않습니다. 이것은 우리가 절대로 아무것도 할 수없는 프로파일 러 식별 핫스팟이있는 프로젝트 (예 : 광산 및 위의 Egor와 같은)에 끔찍합니다. 즉, 코드를 잘라내어 붙여 수동으로 인라인하는 것 외에는 아무것도 없습니다. 한마디로 이것은 성과를 이끌어 갈 때 끔찍한 일입니다.
밝은

6
인라인이 더 미묘합니다. 메모리에는 빠르게 액세스 할 수있는 캐시가 있으며 코드의 현재 부분은 변수와 마찬가지로 해당 캐시에 저장됩니다. 다음 캐시 라인 명령을로드하는 것은 캐시 미스이며 단일 명령보다 10 배 이상 비용이 듭니다. 결국 L2 캐시에로드해야하므로 훨씬 비쌉니다. 따라서 부풀어 오른 코드는 더 많은 캐시 누락을 유발할 수 있으며, 여기서 동일한 L1 캐시 라인에 상주하는 인라인 함수는 캐시 누락을 줄이고 코드가 더 빠를 수 있습니다. .Net을 사용하면 훨씬 더 복잡해집니다.

56

업데이트 :konrad.kruczynski의 대답은 , 다음 .NET 버전의 최대 및 4.0을 포함한 마찬가지입니다.

MethodImplAttribute 클래스사용 하여 메소드가 인라인 되지 않도록 할 수 있습니다 ...

[MethodImpl(MethodImplOptions.NoInlining)]
void SomeMethod()
{
    // ...
}

... 반대를하고 강제 로 인라인 되도록 할 방법이 없습니다 .


2
그것을 알고 흥미롭지 만 왜 도대체 인라인 방법을 방해합니까? 모니터를 쳐다 보는 데 시간을 보냈지 만 인라인이 해를 끼칠 수있는 이유는 없습니다.
Camilo Martin

3
호출 스택 (예 : NullReferenceException)을 수신하고 스택 상단의 메소드가 던질 방법이없는 경우가 있습니다. 물론 전화 중 하나가있을 수 있습니다. 그러나 어느 것?
dzendras

19
GetExecutingAssemblyGetCallingAssembly방법은 인라인 여부에 따라 서로 다른 결과를 제공 할 수 있습니다. 메소드가 인라인되지 않도록 강요하면 불확실성이 줄어 듭니다.
stusmith

1
@Downvoter : 내가 작성한 것에 동의하지 않으면 이유를 설명하는 의견을 게시해야합니다. 그것은 일반적인 예의 일뿐 아니라, 총 20 개 이상의 답변에 투표를함으로써 많은 것을 성취하지 못합니다.
BACON

2
당신의 이름만으로 +1 : D를받을 가치가 있기 때문에 +2를 기원합니다.
retrodrone

33

두 가지 개념을 혼합하고 있습니다. 함수 인라이닝은 의미에 영향을 미치지 않는 컴파일러 최적화입니다. 함수는 인라인 여부에 관계없이 동일하게 동작합니다.

반면에 람다 함수는 순전히 의미 개념입니다. 언어 사양에 명시된 동작을 따르는 한 구현 또는 실행 방법에 대한 요구 사항은 없습니다. JIT 컴파일러가 느낌이 들거나 그렇지 않은 경우 인라인 될 수 있습니다.

C #에는 인라인 키워드가 없습니다. 일반적으로 JIT 언어로 컴파일러에 맡길 수있는 최적화이기 때문입니다. JIT 컴파일러는 런타임 통계에 액세스하여 코드를 작성할 때보 다 훨씬 효율적으로 인라인 할 항목을 결정할 수 있습니다. 컴파일러가 결정하면 함수가 인라인되고 어떤 식 으로든 할 수있는 일이 없습니다. :)


20
"인라인 여부에 관계없이 동일한 기능을 수행합니다." 이것이 사실이 아닌 드문 경우가 있습니다. 즉, 스택 추적에 대해 알고 싶은 로깅 기능입니다. 그러나 나는 당신의 기본 진술을 너무 훼손하고 싶지 않습니다. 그것은 일반적으로 사실입니다.
Joel Coehoorn

"그리고 당신은 어느 쪽의 방법으로도 할 수있는 것이 없습니다."-사실이 아닙니다. 우리가 컴파일러에게 "강력한 제안"을하지 않고 있다고해도 함수가 인라인되는 것을 막을 수 있습니다.
BartoszKP

21

C ++ 의미에서 인라인 함수를 의미합니까? 일반 함수의 내용이 자동으로 호출 사이트에 인라인으로 복사됩니까? 최종 결과는 함수를 호출 할 때 실제로 함수 호출이 발생하지 않는다는 것입니다.

예:

inline int Add(int left, int right) { return left + right; }

그렇다면 no, 이것에 해당하는 C #은 없습니다.

아니면 다른 함수 내에 선언 된 함수를 의미합니까? 그렇다면 C #은 익명 메서드 나 람다 식을 통해이를 지원합니다.

예:

static void Example() {
  Func<int,int,int> add = (x,y) => x + y;
  var result = add(4,6);  // 10
}

21

Cody는 옳지 만 인라인 함수가 무엇인지에 대한 예를 제공하고 싶습니다.

이 코드가 있다고 가정 해 봅시다.

private void OutputItem(string x)
{
    Console.WriteLine(x);

    //maybe encapsulate additional logic to decide 
    // whether to also write the message to Trace or a log file
}

public IList<string> BuildListAndOutput(IEnumerable<string> x)
{  // let's pretend IEnumerable<T>.ToList() doesn't exist for the moment
    IList<string> result = new List<string>();

    foreach(string y in x)
    {
        result.Add(y);
        OutputItem(y);
    }
    return result;
}

컴파일러 적시 최적화이 대신 같은 코드를 작성 것처럼이 될 것이라고 때문에, 스택에 OutputItem ()로 전화를 걸 반복하지 않도록 코드를 변경하도록 선택할 수 있습니다 :

public IList<string> BuildListAndOutput(IEnumerable<string> x)
{
    IList<string> result = new List<string>();

    foreach(string y in x)
    {
        result.Add(y);

        // full OutputItem() implementation is placed here
        Console.WriteLine(y);   
    }

    return result;
}

이 경우 OutputItem () 함수가 인라인되었다고 말할 수 있습니다. 다른 곳에서도 OutputItem ()을 호출하더라도이 작업이 수행 될 수 있습니다.

인라인 될 가능성이 더 높은 시나리오를 표시하도록 편집되었습니다.


9
그래도 명확히하기 위해; 인라인을 수행하는 것은 JIT입니다. C # 컴파일러가 아닙니다.
Marc Gravell

또한 원래 JIT는 최소한 어셈블리 경계에 걸쳐 정적 메소드를 인라인하는 것을 선호합니다. 따라서 최적화를위한 구식 기법은 메서드를 정적으로 표시하는 것이 었습니다. 그 이후로 커뮤니티에 쇄도했지만 오늘날까지도 내부적으로 다형성이 아니며 일반적으로 관련 스택 채우기 + 유출보다 실행 비용이 저렴한 인라인 방법을 선택합니다.
Shaun Wilson

7

예, 정확히 유일한 차이점은 값을 반환한다는 사실입니다.

단순화 (표현식을 사용하지 않음) :

List<T>.ForEach 조치를 취하지 만 리턴 결과를 기대하지 않습니다.

따라서 Action<T>대의원이 충분할 것입니다.

List<T>.ForEach(param => Console.WriteLine(param));

말하는 것과 같습니다.

List<T>.ForEach(delegate(T param) { Console.WriteLine(param); });

차이점은 매개 변수 유형과 대리자 거부가 사용법에 의해 추론되고 간단한 인라인 방법에서는 괄호가 필요하지 않다는 것입니다.

어디로

List<T>.Where 결과를 기대하면서 함수를 취합니다.

따라서 Function<T, bool>예상됩니다 :

List<T>.Where(param => param.Value == SomeExpectedComparison);

이는 다음과 같습니다.

List<T>.Where(delegate(T param) { return param.Value == SomeExpectedComparison; });

이 메소드를 인라인으로 선언하고 변수 IE에 할당 할 수도 있습니다.

Action myAction = () => Console.WriteLine("I'm doing something Nifty!");

myAction();

또는

Function<object, string> myFunction = theObject => theObject.ToString();

string myString = myFunction(someObject);

이게 도움이 되길 바란다.


2

코드를 강제로 인라인하려는 경우가 있습니다.

예를 들어, 매우 반복적 인 블록 내에서 많은 결정이 내려지고 복잡한 결정을 내리는 복잡한 루틴이있는 경우, 그러한 결정으로 인해 비슷하지만 약간 다른 동작이 수행됩니다. 예를 들어, 정렬 알고리즘이 빠른 언어에 대한 의미 적 기준뿐만 아니라 문법에 따라 단어를 정렬하는 경우와 같이 여러 관련되지 않은 여러 기준에 따라 요소를 정렬하는 복잡한 (DB 기반이 아닌) 정렬 비교기를 고려하십시오. 인식 시스템. 소스 코드의 가독성과 모듈성을 유지하기 위해 이러한 작업을 처리하는 도우미 함수를 작성하는 경향이 있습니다.

나는 도우미 함수가 인라인되어야한다는 것을 알고 있습니다. 왜냐하면 그것이 인간이 코드를 이해할 필요가 없다면 코드가 작성되는 방식이기 때문입니다. 이 경우 확실히 함수 호출 오버 헤드가 없었는지 확인하고 싶습니다.


2

"이러한 것들을 내버려두고 컴파일러가 작업을 수행하도록하는 것이 가장 좋습니다."(Cody Brocious)는 완전하지 않습니다. 저는 20 년 동안 고성능 게임 코드를 프로그래밍 해 왔지만 아직 어떤 코드를 인라인 (함수)해야하는지 알 수있는 '똑똑한'컴파일러를 찾지 못했습니다. c #에 "인라인"문을 갖는 것이 유용합니다. 진실은 컴파일러가 "인라인"힌트없이 어떤 함수를 항상 인라인해야하는지 결정하는 데 필요한 모든 정보를 가지고 있지 않다는 것입니다. 함수가 작 으면 (접근 자) 자동으로 인라인 될 수 있지만 몇 줄의 코드이면 어떻게 될까요? 넌센스, 컴파일러는 알 방법이 없으며 최적화 된 코드 (알고 리트 이상)를 컴파일러에 맡길 수는 없습니다.


3
"Nonesense, 컴파일러는 알 방법이 없다"JITer는 실시간으로 함수 호출을 프로파일 링한다.
Brian Gordon

3
.NET JIT는 컴파일 타임에 2 패스 정적 분석으로 가능한 것보다 런타임에 더 잘 최적화하는 것으로 알려져 있습니다. "구식"코더가 이해하기 어려운 부분은 컴파일러가 아닌 JIT가 네이티브 코드 생성을 담당한다는 것입니다. 컴파일러가 아닌 JIT는 인라인 메소드를 담당합니다.
Shaun Wilson

1
소스 코드없이 호출하는 코드를 컴파일 할 수 있으며 JIT가 호출을 인라인하도록 선택할 수 있습니다. 일반적으로 동의하지만 인간 으로서는 더 이상 도구를 능가 할 수 없다고 말하고 싶습니다.
Shaun Wilson


0

아니요, C #에는 그러한 구성이 없지만 .NET JIT 컴파일러는 JIT 시간에 인라인 함수 호출을 수행하도록 결정할 수 있습니다. 그러나 실제로 실제로 그러한 최적화를 수행하는지 여부는 알 수 없습니다.
(필자는 :-)


0

어셈블리를 새로 만들려면 TargetedPatchingOptOut을 살펴보십시오. 이것은 ngen이 메소드를 인라인할지 여부를 결정하는 데 도움이됩니다. MSDN 참조

명령형 명령이 아니라 최적화하는 것은 여전히 ​​암시적인 힌트 일뿐입니다.


그리고 JIT는 인라인 여부에 관계없이 훨씬 더 잘 알 것입니다. JIT가 콜 사이트를 최적화하지 않으면 분명히 도움이되지 않지만 왜 몇 번만 호출되는 함수의 최소 오버 헤드에 대해 걱정해야합니까?
Voo

-7

람다 식은 인라인 함수입니다! C #에는 인라인과 같은 추가 속성이 없습니다.


9
난 당신을 downvote하지 않았지만, 무작위 답변을 게시하기 전에 질문을 읽고 이해했는지 확인하십시오. en.wikipedia.org/wiki/Inline_function
Camilo Martin

1
이 답변은 예상대로 나쁘지 않습니다. OP는 '함수 인라이닝'과 '람다 함수'에 대해 명확하지 않으며 불행히도 MSDN은 람다를 "인라인 문" 또는 "인라인 코드"라고 합니다. 그러나 Konrad의 답변에 따라 메소드 인라인에 대해 컴파일러에게 암시 하는 속성 이 있습니다.
StuartLC

-7

C #은 파이썬과 같은 동적 언어와 같은 방식으로 인라인 메서드 (또는 함수)를 지원하지 않습니다. 그러나 익명 메소드와 람다는 아래 예제와 같이 포함 메소드에서 변수에 액세스해야하는 경우를 포함하여 유사한 목적으로 사용될 수 있습니다.

static void Main(string[] args)
{
    int a = 1;

    Action inline = () => a++;
    inline();
    //here a = 2
}

10
인라인 함수와 관련이있는 것은 무엇입니까? 이것은 익명의 방법입니다.
Tomer W
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.