문제

수율 키워드 중 하나입 키워드 C#을 계속하는 어리둥절,나는 본 적이 없었다는 것을 확신 사용하고 있습니다.

다음 두 개의 코드는 원하는 이유는?

버전 1: 수익률을 사용하여 반환

public static IEnumerable<Product> GetAllProducts()
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        var products = from product in db.Product
                       select product;

        foreach (Product product in products)
        {
            yield return product;
        }
    }
}

버전이 2: 목록을 반환합

public static IEnumerable<Product> GetAllProducts()
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        var products = from product in db.Product
                       select product;

        return products.ToList<Product>();
    }
}
도움이 되었습니까?

해결책

목록에서 다음 항목 (또는 다음 항목 그룹)을 계산할 때 수율 반복을 사용하는 경향이 있습니다.

버전 2를 사용하면 돌아 오기 전에 전체 목록이 있어야합니다. 수율 반복을 사용하면 돌아 오기 전에 다음 항목 만 있으면됩니다.

무엇보다도 이것은 복잡한 계산의 계산 비용을 더 큰 시간에 걸쳐 확산시키는 데 도움이됩니다. 예를 들어, 목록이 GUI에 연결되어 있고 사용자가 마지막 페이지로 이동하지 않으면 목록의 최종 항목을 계산하지 않습니다.

Ienumerable이 무한한 세트를 나타내는 경우 수율 재현이 바람직한 또 다른 경우입니다. 소수 목록 또는 무한한 랜덤 숫자 목록을 고려하십시오. 한 번에 전체 ienumerable을 반환 할 수 없으므로 수율 반복을 사용하여 목록을 점차적으로 반환합니다.

특정 예에서는 전체 제품 목록이 있으므로 버전 2를 사용합니다.

다른 팁

임시 목록을 채우는 것은 전체 비디오를 다운로드하는 것과 같습니다. yield 그 비디오를 스트리밍하는 것과 같습니다.

사용해야 할 때 이해하기위한 개념적 예로 yield, 방법을 가정 해 봅시다 ConsumeLoop() 반환/생성 된 품목을 처리합니다 ProduceList():

void ConsumeLoop() {
    foreach (Consumable item in ProduceList())        // might have to wait here
        item.Consume();
}

IEnumerable<Consumable> ProduceList() {
    while (KeepProducing())
        yield return ProduceExpensiveConsumable();    // expensive
}

없이 yield, 전화 ProduceList() 반환하기 전에 목록을 작성해야하기 때문에 시간이 오래 걸릴 수 있습니다.

//pseudo-assembly
Produce consumable[0]                   // expensive operation, e.g. disk I/O
Produce consumable[1]                   // waiting...
Produce consumable[2]                   // waiting...
Produce consumable[3]                   // completed the consumable list
Consume consumable[0]                   // start consuming
Consume consumable[1]
Consume consumable[2]
Consume consumable[3]

사용 yield, 그것은 재배치되고 일종의 "병렬로"작동합니다.

//pseudo-assembly
Produce consumable[0]
Consume consumable[0]                   // immediately Consume
Produce consumable[1]
Consume consumable[1]                   // consume next
Produce consumable[2]
Consume consumable[2]                   // consume next
Produce consumable[3]
Consume consumable[3]                   // consume next

마지막으로, 이전에 많은 사람들이 이미 제안했듯이, 이미 완료된 목록이 있기 때문에 버전 2를 사용해야합니다.

이것은 기괴한 제안처럼 보일지 모르지만 사용하는 방법을 배웠습니다. yield Python의 발전기에 대한 프레젠테이션을 읽어 C#의 키워드 : David M. Beazley 's http://www.dabeaz.com/generators/generator.pdf. 프레젠테이션을 이해하기 위해 많은 파이썬을 알 필요가 없습니다. 발전기의 작동 방식뿐만 아니라 왜 돌봐야하는지 설명하는 데 매우 도움이되었습니다.

나는 이것이 오래된 질문이라는 것을 알고 있지만, 수율 키워드를 창의적으로 사용하는 방법에 대한 예를 제시하고 싶습니다. 나는 가지고있다 진짜 이 기술로부터 혜택을 받았습니다. 바라건대 이것은이 질문을 우연히 발견하는 다른 사람에게 도움이 될 것입니다.

참고 : 수율 키워드에 대해서는 컬렉션을 구축하는 또 다른 방법이라고 생각하지 마십시오. 수율의 힘의 큰 부분은 실행이 일시 중지 호출 코드가 다음 값을 반복 할 때까지 방법이나 속성에서. 내 예는 다음과 같습니다.

수율 키워드 사용 (Rob Eisenburg와 함께 Caliburn.micro coroutines 구현)은 다음과 같은 웹 서비스에 비동기 호출을 표현할 수 있습니다.

public IEnumerable<IResult> HandleButtonClick() {
    yield return Show.Busy();

    var loginCall = new LoginResult(wsClient, Username, Password);
    yield return loginCall;
    this.IsLoggedIn = loginCall.Success;

    yield return Show.NotBusy();
}

이것이 할 일은 SusyIndicator를 켜고 웹 서비스에서 로그인 메소드를 호출하고 IslogedIn 플래그를 반환 값으로 설정 한 다음 Busy -Indicator를 다시 끕니다.

Iresult에는 실행 방법과 완료된 이벤트가 있습니다. Caliburn.MICRO는 IENUMERATOR를 호출에서 ButtonClick ()를 처리하여 Coroutine.beginexeCute 메소드로 전달합니다. Beginexecute 방법은 노출을 통해 반복을 시작합니다. 첫 번째 iResult가 반환되면 handlbuttonclick () 내부에서 실행이 일시 중지되고 BegineXecute ()는 이벤트 핸들러를 완성 된 이벤트에 첨부하고 execute ()를 호출합니다. iresult.execute ()는 동기식 또는 비동기 작업을 수행하고 완료된 이벤트를 수행 할 수 있습니다.

loginresult는 다음과 같이 보입니다.

public LoginResult : IResult {
    // Constructor to set private members...

    public void Execute(ActionExecutionContext context) {
        wsClient.LoginCompleted += (sender, e) => {
            this.Success = e.Result;
            Completed(this, new ResultCompletionEventArgs());
        };
        wsClient.Login(username, password);
    }

    public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
    public bool Success { get; private set; }
}

이와 같은 것을 설정하고 실행을 통해 무슨 일이 일어나고 있는지 보는 것이 도움이 될 수 있습니다.

이것이 누군가를 도울 수 있기를 바랍니다! 나는 수확량을 사용할 수있는 다양한 방법을 탐색하는 것을 정말로 즐겼습니다.

수백만 개의 객체를 반복 해야하는 알고리즘의 경우 수율 수익률이 매우 강력 할 수 있습니다. Rideshare를위한 가능한 여행을 계산 해야하는 다음 예제를 고려하십시오. 먼저 가능한 여행을 생성합니다.

    static IEnumerable<Trip> CreatePossibleTrips()
    {
        for (int i = 0; i < 1000000; i++)
        {
            yield return new Trip
            {
                Id = i.ToString(),
                Driver = new Driver { Id = i.ToString() }
            };
        }
    }

그런 다음 각 여행을 통해 반복하십시오.

    static void Main(string[] args)
    {
        foreach (var trip in CreatePossibleTrips(trips))
        {
            // possible trip is actually calculated only at this point, because of yield
            if (IsTripGood(trip))
            {
                // match good trip
            }
        }
    }

수율 대신 목록을 사용하는 경우 메모리에 1 백만 개 객체를 할당해야 하며이 간단한 예제는 ~ 1400ms를 실행하는 데 걸립니다. 그러나 수율을 사용하는 경우 이러한 모든 임시 객체를 메모리에 넣을 필요가 없으며 알고리즘 속도가 훨씬 빨라질 것입니다.이 예제는 메모리 소비없이 실행하는 데 ~ 400ms 만 필요합니다.

두 개의 코드가 정말 하고 다른 두 가지입니다.첫번째 버전 풀 구성원으로 당신은 그들이 필요합니다.두번째 버전을 로드하는 모든 결과로 메모리 당신은 시작은 아무것도 할 필요합니다.

아무 권리 또는 잘못된 응답을 이 하나입니다.하나는 것이 바람직 그냥 상황에 따라 달라집니다.예를 들어,는 경우에는 제한이 있는 시간이 있을 완료하는 쿼리고 당신이 무언가를 할 필요가 반 복잡한 결과 함께,두번째 버전이 될 수 있는 것이 바람직하다.하지만 조심 큰 결과,특히 실행하는 경우 이 코드에서 32 비트 모드이다.나에게 물린 OutOfMemory 예외를 몇 시간을 할 때 이 방법입니다.

에 이상을 유지해야 한다는 것에 마음이만:차이가 있습니다.따라서,당신은 당신이해야 중 하나는 당신의 코드 간단하고 그것을 변경한 후에만 프로파일링입니다.

수율은 두 가지 큰 용도를 가지고 있습니다

임시 컬렉션을 만들지 않고 맞춤형 반복을 제공하는 데 도움이됩니다. (모든 데이터로드 및 루핑)

상태의 반복을 수행하는 데 도움이됩니다. (스트리밍)

아래는 위의 두 지점을 지원하기 위해 전체 데모로 만든 간단한 비디오입니다.

http://www.youtube.com/watch?v=4fju3xcm21m

이것이 무엇입니다 Chris는 판매합니다 그 진술에 대해 이야기합니다 C# 프로그래밍 언어;

나는 때때로 수익률 수익률이 수익률 수익률을 실행할 수 있다는 점에서 수익률 수익률이 반환과 같지 않다는 것을 잊어 버린다. 예를 들어, 여기에서 첫 번째 반환 후 코드를 실행할 수 없습니다.

    int F() {
return 1;
return 2; // Can never be executed
}

대조적으로, 여기에서 첫 번째 수익률 반환 후 코드를 실행할 수 있습니다.

IEnumerable<int> F() {
yield return 1;
yield return 2; // Can be executed
}

이것은 종종 if 진술에 나를 물었다.

IEnumerable<int> F() {
if(...) { yield return 1; } // I mean this to be the only
// thing returned
yield return 2; // Oops!
}

이 경우, 수익률 수익률은 수익률이 도움이되는 것처럼 "최종"이 아니라는 것을 기억합니다.

제품 LINQ 클래스가 열거/반복을 위해 유사한 수익률을 사용한다고 가정하면 첫 번째 버전은 반복 할 때마다 하나의 값만 생성하기 때문에 더 효율적입니다.

두 번째 예제는 열거 자/반복기를 Tolist () 메소드를 사용하여 목록으로 변환하는 것입니다. 이는 열거 자의 모든 항목을 수동으로 반복 한 다음 평평한 목록을 반환한다는 것을 의미합니다.

이것은 요점 외에도 다소 이루어 지지만 질문에 베스트 프로이크가 태그가 지정되므로 2 센트를 던져 버릴 것입니다. 이런 유형의 것에 대해 나는 그것을 속성으로 만들기를 크게 선호합니다.

public static IEnumerable<Product> AllProducts
{
    get {
        using (AdventureWorksEntities db = new AdventureWorksEntities()) {
            var products = from product in db.Product
                           select product;

            return products;
        }
    }
}

물론 보일러 판이 조금 더 있지만이를 사용하는 코드는 훨씬 더 깨끗해 보입니다.

prices = Whatever.AllProducts.Select (product => product.price);

vs

prices = Whatever.GetAllProducts().Select (product => product.price);

메모: 나는 그들의 일을하는 데 시간이 걸리는 방법에 대해서는 이것을하지 않을 것입니다.

그리고 무엇을 이?

public static IEnumerable<Product> GetAllProducts()
{
    using (AdventureWorksEntities db = new AdventureWorksEntities())
    {
        var products = from product in db.Product
                       select product;

        return products.ToList();
    }
}

나는 생각이 깨끗합니다.내가하지 않 VS2008 에서 확인하는 반면,하지만.어떤 경우에,제품 구현페(하는 것으로-그것은에서 사용 foreach 서),으로 다시 돌아갈 것이라 그 모습을 볼 수 있습니다.

이 경우 코드의 버전 2를 사용했을 것입니다. 사용 가능한 제품의 전체 목록이 있으며 이것이이 방법 호출의 "소비자"가 기대하는 것이므로 전체 정보를 발신자에게 다시 보내야합니다.

이 메소드의 발신자가 한 번에 "하나의"정보가 필요하고 다음 정보의 소비가 주문형 기준이면, 수율 수익률을 사용하는 것이 유리합니다. 정보 단위를 사용할 수 있습니다.

수율 수익률을 사용할 수있는 몇 가지 예는 다음과 같습니다.

  1. 발신자가 한 번에 단계의 데이터를 기다리는 복잡한 단계별 계산
  2. GUI의 페이징 - 사용자가 마지막 페이지에 도달 할 수없고 현재 페이지에 공개 해야하는 정보 만 공개해야합니다.

귀하의 질문에 답하기 위해 버전 2를 사용했을 것입니다.

목록을 직접 반환하십시오. 이익:

  • 더 분명합니다
  • 목록은 재사용 가능합니다. (반복자는 그렇지 않습니다) 사실이 아닙니다. 감사합니다 Jon

목록의 끝까지 또는 끝이 없을 때 반복 할 필요가 없다고 생각할 때부터 반복자 (수율)를 사용해야합니다. 예를 들어, 클라이언트 호출은 일부 술어를 만족시키는 첫 번째 제품을 검색 할 예정이지만 반복자를 사용하는 것을 고려할 수 있지만, 이는 예를 들어 보이지만이를 달성하는 더 좋은 방법이있을 수 있습니다. 기본적으로, 전체 목록을 계산해야한다는 것을 미리 알고 있다면, 앞에서 만하십시오. 그렇지 않다고 생각되면 반복자 버전을 사용하는 것을 고려하십시오.

수율 리턴 키 프레이즈는 특정 컬렉션의 상태 머신을 유지하는 데 사용됩니다. CLR이 수율 리턴 키 프레이즈를 사용하는 것을 볼 때마다 CLR은 해당 코드에 열거적 패턴을 구현합니다. 이러한 유형의 구현은 키워드가없는 경우 다른 유형의 배관을 개발하는 데 도움이됩니다.

개발자가 일부 컬렉션을 필터링하고 컬렉션을 반복 한 다음 새로운 컬렉션에서 해당 객체를 추출한다고 가정합니다. 이런 종류의 배관은 매우 단조롭습니다.

더 많은 것에 대해 이 기사의 키워드.

의 사용 생산하다 키워드와 유사합니다 반품, 그것이 반환한다는 것을 제외하고 발전기. 그리고 발전기 물체는 단지 가로 질러옵니다 한 번.

생산하다 두 가지 이점이 있습니다.

  1. 이 값을 두 번 읽을 필요는 없습니다.
  2. 많은 어린이 노드를 얻을 수 있지만 모두 메모리에 넣을 필요는 없습니다.

또 다른 명확성이 있습니다 설명 어쩌면 당신을 도와 줄 수도 있습니다.

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