Способы расширения при первом вызове медленнее, чем при последующих вызовах - PullRequest
0 голосов
/ 11 августа 2010

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

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

Спасибо, wTs

Код выглядит примерно так:

Тестовый код

void TestCode()
{
    for (int i = 0; i < iterationsPerLoop; i++)
    {
        DateTime startTime = DateTime.Now;

        // The test is actually being done in a BackgroundWorker
        dispatcher.Invoke(DispatcherPriority.Normal,
                            (Action)(() => this.PropertyCausingCodeToRun = "Run";
        while (this.WaitForSomeCondition)
            Thread.Sleep(125);
        DateTime endTime = DateTime.Now;

        double result = endTime.Subtract(startTime).TotalSeconds;
    }
}

Метод, в котором методы расширения называются

private static List<ObservableItem> GetAvailableItems(MyObject myObject)
{
    var items = new List<ObservableItem>(myObject.Items.ToList());
    var selectedItems = items.OrderByDescending(item => item.ASortableProperty)
                             .SetItemIsAvailable(false)
                             .SetItemPriority() 
                             .OrderByDescending(item => item.Priority) 
                             .Where(item => item.Priority > 0) 
                             .SetItemIsAvailable(true) 
                             .OrderBy(item => item.Date);

    return selectedItems.ToList();
}

Методы расширения (все объекты ObservableItems созданы в другом потоке)

static class MyExtensionMethods
{
    public static IEnumerable<T> SetItemIsAvailable<T>(this IEnumerable<T> sourceList,
            Boolean isAvailable) where T : ObservableItem
    {
        Action<T> setAvailable = i => i.IsAvailable = isAvailable;

        List<DispatcherOperation> invokeResults = new List<DispatcherOperation>();

        foreach (var item in sourceList)
        {
            invokeResults.Add(
                item.ItemDispatcher.BeginInvoke(setAvailable , new object[] { item }));
        }

        invokeResults.ForEach(ir => ir.Wait());
        return sourceList;
    }

    public static IEnumerable<T> SetItemPriority<T>(this IEnumerable<T> sourceList) where T : ObservableItem
    {
        Action<T, double> setPriority = new Action<T, double>((item, priority) =>
            {
                item.Priority = priority;
            });

        List<DispatcherOperation> invokeResults = new List<DispatcherOperation>();

        foreach (var item in sourceList)
        {
            double priority = ......;  // Some set of calculations

            invokeResults.Add(
                item.ItemDispatcher.BeginInvoke(setPriority, 
                            new object[] { asset, priority }));
        }

        invokeResults.ForEach(ir => ir.Wait());
        return sourceList;
    }
}

Ответы [ 2 ]

4 голосов
/ 11 августа 2010

Чаще всего при первом вызове методов возникают некоторые накладные расходы, связанные со временем компиляции JIT.Это будет иметь эффект (хотя, скорее всего, не так сильно).

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

Я бы рекомендовал выполнять все ваши операции за один диспетчерский вызов и использовать Invoke вместо BeginInvoke.Вместо того, чтобы сортировать одно сообщение для каждого элемента, просто выполните маршалинг одного делегата, который включает цикл foreach для всех ваших элементов.

Это будет значительно быстрее.

0 голосов
/ 11 августа 2010

Реальная проблема, как я выяснил, была вызвана тем, что изначально свойство вызывалось для сортировки элементов (еще до вызова методов расширения).

Свойство имеет вид:

public Double ASortableProperty
{
    get
    {
        if (mASortableProperty.HasValue)
        {
            return mASortableProperty.Value;
        }
        mASortableProperty = this.TryGetDoubleValue(...);
        return (mASortableProperty.HasValue ? mASortableProperty.Value : 0);
    }
}

Таким образом, при первом прохождении цикла значения не были инициализированы из базы данных, и затраты были получены для извлечения этих значений, прежде чем можно будет выполнить сортировку.

...