плз помогите оптимизировать небольшой фрагмент кода, VS2010 график профилирования при условии


Профилирование показывает метод MoveNext занимает большую часть времени, который я предполагаю, правда, как он ленив. Но я не знаю в каком направлении я мог бы улучшить код. (Открыть картинку в новой вкладке позволит увидеть больше график.)

enter image description here

    IEnumerable<string> MixedBlock(List<string> reelLayout, string thisBlock, int length)
    {
        List<string> recentBlock = RecentBlock(length - 1, reelLayout);
        var upper = Enumerable.Range(1, length - 1);
        var lower = Enumerable.Range(1, totalWeight[thisBlock].Num);
        var query = from x in upper
                    from y in lower
                    where x + y == length
                    select Tuple.Create(x, y);
        foreach (var t in query)
        {
            string upperBlock = string.Join(",", recentBlock.Skip(length - 1 - t.Item1));
            string lowerBlock = string.Join(",", thisBlock.Split(',').Take(t.Item2));
            yield return upperBlock + "," + lowerBlock;
        }

    }


394
5
c#
задан 25 августа 2011 в 07:08 Источник Поделиться
Комментарии
3 ответа

Вы делаете больше повторений, чем необходимо.. вам не нужно 2 enumerables из ИНЦ только для этого нужно, это много больше кучи справок, когда все ваши потребности будут 2 числа на стеке, и вложенный цикл for:

int upperLimit = length - 1;
int lowerLimit = totalWeight[thisBlock].Num;
List<string> recentBlock = RecentBlock(length - 1, reelLayout);
List<string> stringResults = new List<string>();

for(int upper = 1; upper < upperLimit; upper++)
{
for(int lower = 1; lower < lowerLimit; lower++)
{
if (upper + lower = length)
{
stringResults.Add(
string.Join(",", recentBlock.Skip(length - 1 - upper)) + "," +
string.Join(",", splits.Take(lower)));
}
}
}

return stringResults;

также вместо того, чтобы stringResults.Добавить можно только урожайность вернуть строку прямо там, если вы хотели, чтобы с отсроченным исполнением.

Помните, только потому, что сейчас мы имеем кортежи и все счастливы linqiness, они могут быть использованы для упрощения сложных вещей, хоть иногда они просто делают операции более сложные. Если важна производительность, на то, что происходит под LINQ, которая, прежде чем выбросить его вокруг слишком много.

3
ответ дан 25 августа 2011 в 11:08 Источник Поделиться

Я считаю, что есть проблема с метод MoveNext() от перечислитель, который возвращается из MixedBlock(). Его метод MoveNext() просто не много ленивый обработки, но не кэширует результаты на всех.

(1). Когда вы iterare за результат от MixedBlock() вашей итерации с помощью автоматически сгенерированный класс, который реализует IEnumerable и IEnumerator. Его метод MoveNext() является тяжелой функцией, потому что оно должно создать все функции anononymouse в код, поддерживать состояние и делегировать вызовы к перечислитель от метода SelectMany(). Вы можете избежать этого путем устранения этой доходности сайта.

(2). Удаление доходность сайта также позволит компилятор не генерировать примеры вспомогательных функций, но использовать только extenssion методов. Теперь она может выглядеть так

            if (MyClass.CS$<>9__CachedAnonymousMethodDelegate5 == null)
{
MyClass.CS$<>9__CachedAnonymousMethodDelegate5 = new Func<int, int, <>f__AnonymousType0<int, int>>(MyClass.<MixedBlock>b__2);
}
if (MyClass.CS$<>9__CachedAnonymousMethodDelegate6 == null)
{
MyClass.CS$<>9__CachedAnonymousMethodDelegate6 = new Func<<>f__AnonymousType0<int, int>, bool>(MyClass.<MixedBlock>b__3);
}
if (MyClass.CS$<>9__CachedAnonymousMethodDelegate7 == null)
{
MyClass.CS$<>9__CachedAnonymousMethodDelegate7 = new Func<<>f__AnonymousType0<int, int>, int>(MyClass.<MixedBlock>b__4);
}

(3). Перед входом по каждому элементу за запросов я бы рекомендовал для кэширования результатов предыдущих проекции.

var query = from x in upper
from y in lower
where x + y == length
select Tuple.Create(x, y).ToList();

(4). Это заявление может быть вычислено только один раз при входе в функцию. Однако вы делаете ту же работу, на каждой итерации.

  thisBlock.Split(',')

Все в одном вы можете иметь что-то подобное.

IEnumerable<string> MixedBlock(List<string> reelLayout, string thisBlock, int length)
{
List<string> result = new List<string>();

string[] splits = thisBlock.Split(',');
List<string> recentBlock = RecentBlock(length - 1, reelLayout);
var upper = Enumerable.Range(1, length - 1);
var lower = Enumerable.Range(1, totalWeight[thisBlock].Num);
var query = from x in upper
from y in lower
where x + y == length
select Tuple.Create(x, y).ToList();
foreach (var t in query)
{
string upperBlock = string.Join(",", recentBlock.Skip(length - 1 - t.Item1));
string lowerBlock = string.Join(",", splits.Take(t.Item2));
results.Add(upperBlock + "," + lowerBlock);
}

return (results);
}

Я пробовал оба подхода на код с аналогичной структурой в моем случае вроде бы 20% быстрее.

1
ответ дан 25 августа 2011 в 09:08 Источник Поделиться

Я думаю, что ты делаешь вторую петлю, что вы не математически нужно.

where x + y == length

Поэтому

x = length - y

Поскольку длина является фиксированной и Y является переменной. х, кажется, должны быть рассчитаны просто для удовлетворения где, и поэтому могут быть удалены как итератор и просто вычисляется.

Также верхняя петля только на длину-1, так что если общим весом[этотблок].Кол-во больше, то лучше использовать его.

var lower = Enumerable.Range(1, Math.Min(totalWeight[thisBlock].Num, length-1));
var query = from y in lower
select Tuple.Create(length - y, y);

Это также сворачивает LINQ-запрос, которая, в свою очередь, позволяет нам удалить Кортеж. Вместо этого мы можем просто обычную (Длина - м) везде, где нужен оригинал х.

var lower = Enumerable.Range(1, Math.Min(totalWeight[thisBlock].Num, length-1));
foreach (var t in lower)
{
string upperBlock = string.Join(",", recentBlock.Skip(length - 1 - (length-y)));
string lowerBlock = string.Join(",", thisBlock.Split(',').Take(y));
yield return upperBlock + "," + lowerBlock;
}

Поверните перечисли.Серии/циклы foreach в цикле for.
Также длина - 1 - (Длина-м) становится г - 1

for (int y = 1; y <= Math.Min(totalWeight[thisBlock].Num, length-1); y++)
{
string upperBlock = string.Join(",", recentBlock.Skip(y - 1));
string lowerBlock = string.Join(",", thisBlock.Split(',').Take(y));
yield return upperBlock + "," + lowerBlock;
}

Оптимизировать из раздела этотблок просто так это не сделать в цикле.

Также объединить строки объединяются в 1 функции, используя метод concat.

Так что вы в конечном итоге с...

IEnumerable<string> MixedBlock(List<string> reelLayout, string thisBlock, int length)
{
List<string> recentBlock = RecentBlock(length - 1, reelLayout);
var thisSplitBlock = thisBlock.Split(',');
for (int y = 1; y <= Math.Min(totalWeight[thisBlock].Num, length-1); y++)
{
yield return string.Join(",",
recentBlock.Skip(y - 1)
.Concat(thisSplitBlock.Take(y));
}
}

Примечание: это позволит вывести элементы в обратном порядке от оригинала. Если порядок важен, просто обратить на петли.

for (int y = Math.Min(totalWeight[thisBlock].Num, length-1); y >= 1; y--)

0
ответ дан 1 сентября 2011 в 03:09 Источник Поделиться