C # derleyicisi bu iç içe geçmiş LINQ sorgusunda neden çıldırıyor?


97

Aşağıdaki kodu derlemeyi deneyin ve derleyicinin> 3 GB RAM (makinemdeki tüm boş bellek) ve derlemesi çok uzun sürdüğünü (aslında 10 dakika sonra IO istisnası alıyorum) göreceksiniz.

using System;
using System.Linq;

public class Test
{
    public static void Main()
    {
        Enumerable.Range(0, 1).Sum(a =>
        Enumerable.Range(0, 1).Sum(b =>
        Enumerable.Range(0, 1).Sum(c =>
        Enumerable.Range(0, 1).Sum(d =>
        Enumerable.Range(0, 1).Sum(e =>
        Enumerable.Range(0, 1).Sum(f =>
        Enumerable.Range(0, 1).Count(g => true)))))));
    }
}

Bu tuhaf davranışı kimse açıklayabilir mi?

CS Sürümü: Microsoft (R) Visual C # Derleyici sürüm 4.0.30319.17929
İşletim Sistemi Adı: Microsoft Windows 7 Ultimate
İşletim Sistemi Sürümü: 6.1.7601 Service Pack 1 Build 7601

Hafıza kullanımı


5
İyi karar! Kodu görsel stüdyoya yapıştırdım ve 32 bitlik bir işlemin izin verdiği ve ardından çöktüğü tüm 4Gb'yi tüketti (Windows 8.1'de 2013 Ultimate).
satnhak

2
Bu kodu paylaşılan bir kod tabanına ekleyin (not defteri kullanarak) ve iş arkadaşlarınızın makinelerinin çökmesini izleyin.
usr

3
Microsoft Connect hakkında ve derleyicilerinin aynı davranışı sergilemesi durumunda Roslyn ekibine rapor vermek iyi bir şey gibi görünüyor.
Trillian'ın

3
Eric Lippert'in bir yerlerde (nerede olduğunu hatırlamıyorum) dediğini duyduğuma inanıyorum, lambdaları çok sık tip çıkarımıyla iç içe geçirmenin derleyicide bazı kötü baş ağrılarına neden olabilir. Onu nerede gördüğümü düşünemiyorum, bu yüzden bir referans veremiyorum. Umarım adam bunu görebilir ve yorum yapabilir ...
Chris

2
Aferin, düzeltin ve bunun için güzel bir cevabınız olabilir: En sevdiğiniz derleyiciyi
Nathan Cooper

Yanıtlar:


40

Bunun tür çıkarımı ve / veya lambda üretimi ile ilgili olduğuna inanıyorum (tür çıkarımının normale ters yönde gitmesi gerektiğinde), aşırı yük çözünürlüğü ile birlikte. Ne yazık ki, sadece tip parametrelerini sağlamak duruma yardımcı olmuyor (muhtemelen hala tip kontrolünü yapmak zorunda olduğu durumda).

Lambdalar analiz edildikten sonra mantıksal olarak sizinkinden eşdeğer kod olması gereken aşağıdaki kod sorunsuz bir şekilde derlenir:

static void Main()
{
    var x = Enumerable.Range(0, 1).Sum(a);
}

private static int a(int a)
{
    return Enumerable.Range(0, 1).Sum(b);
}
private static int b(int b)
{
    return Enumerable.Range(0, 1).Sum(c);
}
private static int c(int c)
{
    return Enumerable.Range(0, 1).Sum(d);
}
private static int d(int d)
{
    return Enumerable.Range(0, 1).Sum(e);
}
private static int e(int e)
{
    return Enumerable.Range(0, 1).Sum(f);
}
private static int f(int f)
{
    return Enumerable.Range(0, 1).Count(g);
}
private static bool g(int g)
{
    return true;
}

Eric Lippert'in bu tür çıkarımının C # derleyicisinde (bazı problemlerin) derleyiciyi NP-Complete problemini çözmeye zorlayabileceği ve tek gerçek stratejisinin (burada olduğu gibi) kaba kuvvet olduğu yerlerden daha önce yayınladığına inanıyorum. İlgili referansları bulabilirsem buraya ekleyeceğim.


Bulabildiğim en iyi referans, burada Eric'in gerçek maliyete neden olan aşırı yük çözümleme çalışması olduğu gerçeğini tartıştığı yer - hatırlayın, Enumerable.Sum'un lambda / yöntemi kabul eden 10 aşırı yüklemesi var.


1
Yani, temel olarak, derleyici, 10^nkombinasyonlarda ( nzincirleme yöntemlerin miktarı) kendi yolunu bulur . Makul geliyor (yani bir açıklama olarak).
DarkWanderer

1
@DarkWanderer:that^numberofpossibletypes
leppie

@Damien_The_Unbeliever, senin düşünce anlamak dikişleri gerçekten makul (bu arada kod derleme değil )
Eugene D. Gubenkov

15
Buradaki analiziniz doğru. Her lambda, on olası aşırı yükleme faktörü sunar ve tüm kombinasyonlar kontrol edilmelidir. Kombinasyon sayısı arttığında boşa çıkan ancak onu hiçbir zaman uygulamayan bir kod eklemeyi düşündüm.
Eric Lippert

2
@EricLippert Çekme talebi zamanı! : D
Rob H
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.