История одного Intersect-а

26 Сен
2011

Краткая предыстория: разрабатываем большой, долгоживущий проект, переданный нам на outsource. Соответственно, часто приходится заниматься оптимизацией чужого кода, но один случай поставил в тупик не только меня, но и всю команду…
В процессе отладки кода, наткнулся на жутко неоптимальное место, в котором поиск дочерних элементов дерева производился двойным перебором. На больших деревьях алгоритм подвисал на несколько часов, что ну никак не устраивало заказчика.
Было принято решение, строить виртуальное дерево. Дерево построил, прогнал профайлером проблемный код. Все отлично, за исключением одного момента – для фильтрации найденных дочерних элементов использовался Intersect, который почему-то страшно тормозил. Самое удивительное, что замена Intersect-а на Where изменила ситуацию кардинально! Смотрите сами:
image
Но ведь такого быть не может – Intersect и Where должны работать примерно одинаково! Стал искать причину… Сперва отключил профайлер, запустил программу, замерял время – вариант с Where действительно работает намного быстрее, т.е. дело не в профайлере. Что ж, создал тестовый консольный проект, запустил и очень крепко задумался – тесты показали, что Intersect на больших объемах работал даже быстрее Where! Неужели мир сошел сума – не может же наша программа как-то по-особому работать с LINQ!?
Тут меня осенило! Ведь это дерево, а это значит, что childrenList часто будет пустым при поиске дочерних элементов в листьях. Еще один тест и вуаля – причина найдена!
Итак, что мы имеем. Intersect медленно работает с пустыми коллекциями – факт. Но настолько ли это критично? В подавляющем большинстве случаев – не играет роли, но мне попался другой случай. И знаете, я этому рад – хороший повод запостить первую статью на любимом Блоге.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх