2015-11-19 3 views
6

Я рассмотрел код коллег и сказал ему переупорядочить логические сравнения в следующем предикате Linq Any по соображениям производительности. Поэтому, учитываяПорядок оценки C#

public class JobResult 
{ 
    public JobResult(); 

    public string Id{ get; set; } 
    public StatusEnum Status{ get; set; } 
    public string JobType{ get; set; } 
} 

и

IList<JobResult> jobsList = _jobRepository.FetchJobs() 

Я предложил изменить следующее:

//Exit if there is already a job of type "PurgeData" running 
if (jobsList.Any(job => job.Status == JobStatus.Running //1 
        && job.Id != currentJobId   //2 
        && job.JobType == "PurgeData")) //3 
    return false; 

стать

//Exit if there is already a job of type "PurgeData" running 
if (jobsList.Any(job => job.JobType == "PurgeData"  //3 
        && job.Status == JobStatus.Running //1 
        && job.Id != currentJobId))    //2 
    return false; 

Мои рассуждения в том, что большинство рабочих мест в jobsList неудачу тест для JobType, только некоторые из них не пройдут тест для Running, и только один пропустит тест для Id. Если совпадение не выполняется, нет смысла оценивать остальные, и из-за точек последовательности это не произойдет.

Мой вопрос состоит из трех частей: это правда, верно ли это, и есть ли лучшее объяснение, которое я могу дать моему коллеге за то, почему переупорядочение - хорошая идея?

+3

Имейте в виду, что сравнение 'int' или' enum' включает в себя единую машинную инструкцию, тогда как сравнение строк намного сложнее. –

+1

Вы можете доказать это, переведя каждое предложение в функцию и внутри этой функции вывести на журнал или 'Console.WriteLine' для примера. – DavidG

+0

Я бы поставил сравнение строк последним. Думать о чем-то труднее об этом было бы пустой тратой времени. Сравнение между двумя целями один или два раза не будет вашим узким местом. – SimpleVar

ответ

7

Мое рассуждение состояло в том, что большая часть заданий в jobsList не проходит тест для JobType, только некоторые из них не пройдут тест для Running, и только один не пройдет тест для Id. Если совпадение не выполняется, нет смысла оценивать остальные, и из-за точек последовательности это не произойдет. Это правда?

Верно ли, что второй и третий предикаты не будут оцениваться, если первый является ложным? Да. Ваши рассуждения верны.

Верно ли, что избежать оценки второго и третьего предикатов, когда первое является ложным, является явным выигрышем в производительности? Не обязательно, по двум причинам.

Во-первых, не все сравнения одинаково дороги. Сравнение строк «PurgeData» и «PurgeDatz» требует сравнения восьми символов перед спасением; сравнение целых чисел дешевле. Это может быть в среднем случае дешевле, чтобы избежать сравнения строк, даже если оно более вероятно, будет ложным.

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

Смотрите мою недавнюю статью на эту тему:

http://ericlippert.com/2015/11/02/when-would-you-use-on-a-bool/

есть лучшее объяснение, которое я могу дать моему коллеге за почему переназначения это хорошая идея?

Да. Вы можете установить метрику производительности и реалистичную, важную цель, ориентированную на клиента, вы можете продемонстрировать эмпирически, что код один из способов не соответствует вашей цели при измерении в соответствии с метрикой, и вы можете эмпирически показать, что код соответствует вашей цели, когда вы пишете это по-другому.

Если вы этого не сделаете, то то, что вы описываете, - это разница, которую вы не можете измерить, и никто не заботится; ваш коллега был бы совершенно прав сказать вам прекратить тратить время на изменение рабочего кода, чтобы изменить ситуацию, которую вы не можете измерить, о которой никто не заботится.

+0

Желаю, чтобы больше людей понимали, что попытка оптимизировать код без измерения/профилирования/цели цели - бесплодное упражнение. Если бы у меня была копейка за каждый раз, когда кто-то предлагал изменить этот код, я могу легко уйти в отставку. – SolutionYogi

+0

Насыщенные точки @ Эрик, но я не писал никакого кода, чтобы проверить что-либо. Если бы я знал, что оптимизация была бы оправдана в общем случае, я бы всегда структурировал свой код таким образом. Я пропустил расходы на сравнение строк, но потом именно поэтому я здесь ..., чтобы получить образование по обычному правилу. Теперь я могу применить эту аргументацию в будущем и знаю, что я не могу экономить циклы процессора, но я тоже не трачу. – cl0h

4

Мое рассуждение состояло в том, что большинство заданий в jobsList не прошли тест для JobType, только некоторые из них не пройдут тест для Running, и только один не завершит проверку Id. Если совпадение не выполняется, нет смысла оценивать остальные, и из-за точек последовательности это не произойдет.

Да, || и && операторы short-circut в C#. Значит, они не будут продолжать оценивать другие выражения, если условие уже выполнено. Учитывая, что JobType оценивает до false, другие предикаты не будут вычислены. Обратите внимание, что ваш код может иметь дополнительные накладные расходы, которые перевешивают переупорядочение этих предикатов, например сравнение int против string (где последний, скорее всего, будет дороже).

Это относится к категории микрооптимизаций и, кроме объяснения того, что короткое замыкание для вашего коллеги, я предлагаю вам проверить этот код, чтобы убедиться, что он вообще обеспечивает какое-либо преимущество в производительности.

+0

Короткое замыкание - это концепция, о которой я думал. Спасибо – cl0h

+1

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

4

Лично я бы не против этого. Накладные расходы на использование LINQ намного больше, чем само сравнение. И если первый предикат оценивается как false, все остальные игнорируются, поэтому тестирование наименее вероятного - это хорошая идея.

Оценивая стоимость оценки, перечисления являются целыми числами, поэтому сравнение перечисления дешевле, чем оценка строки в целом. Вторая оценка также является целым числом, поэтому меньше, чем сравнение строки. Я думал, string сравнил длину во-первых, так что это было бы тоже целочисленное сравнение, сравнение каждого символа стоило бы больше. Поэтому, если строка одинаково длинна, где ее сравнивают, оценка строки тяжелее целых чисел. Иначе это не имеет большого значения.

+0

Некоторые полезные соображения здесь. Я предлагаю изменить тип JobType из строки в перечисление. Похоже, что это обеспечит более высокую производительность, чем переупорядочение. – cl0h

+0

Действительно. Если возможно, это будет вариант. –

0

Очень легко тратить часы на оптимизацию вещей, которые не замедляются.

Если вам нужно спросить, какой метод работает быстрее, вы не можете сказать разницу (то есть, оба достаточно быстры).

Запросы Linq иногда преобразуются в SQL, поэтому скорость может зависеть от внутренней реализации вашей базы данных, которая не поддается контролю.

Смежные вопросы