2013-04-30 2 views
3

Есть ли причина, по которой F # недостаточно умна, чтобы оптимизировать следующий код? fast = 880 и slow = 8090.Оптимизация доступа к значениям функций в записи с использованием F #

type Data = { fn: int * int -> int } 
let fn (x, y) = x + y 
let data = { fn = fn } 

let mutable a = 0 
let s = System.Diagnostics.Stopwatch() 

s.Start() 
for i in 0 .. 1000000000 do 
    a <- fn(i, i) 
printfn "fast = %d" s.ElapsedMilliseconds 

s.Restart() 
for i in 0 .. 1000000000 do 
    a <- data.fn(i, i) 
printfn "slow = %d" s.ElapsedMilliseconds 
+0

Я думаю, что ваш вопрос не совсем прав. Правильный вопрос - почему _doesn't_ установщик оптимизирует его, а не почему _can't_ он оптимизирует его. – mydogisbox

ответ

7

Есть ли причина, почему F # не достаточно умны, чтобы оптимизировать следующий код?

Я был бы удивлен, если компилятор F # сможет оптимизировать этот случай. В конце, fn - это поле записи, которое предназначено для хранения данных, а не для выполнения функций.

Даже на нестатических элементах компилятор не может встроить их, поскольку эти члены ограничены изменением среды. Объявляя привязку let, у вас есть преимущество статической среды, и компилятор может встроить в некоторые простые случаи.

Действительно, в этом примере функция fn встроена (добавление inline не меняет время работы). Медленным примером является цена, которую вы платите за более мощную конструкцию.

Всякий раз, когда вы должны создать запись функций, помните, что интерфейсы и выражения объекта лучшие альтернативы (меньше накладные расходы, лучше IntelliSense):

type Data2 = 
    abstract fn : int * int -> int 

let data2 = 
    { new Data2 with 
     member __.fn (x, y) = fn (x, y) } 

s.Restart() 
for i in 0 .. 1000000000 do 
    a <- data2.fn(i, i) 
printfn "a bit slow = %d" s.ElapsedMilliseconds 

Это результат я получил, выполнив в F # Interactive 64 -битовый:

fast = 614 
slow = 7498 
a bit slow = 2765 

Так подход интерфейс на основе является 3x быстрее, чем подход на основе записей и 3x медленнее, чем метод инлайн.

4

Быстрый путь встраивание fn, но медленный путь делает вызов функции.

Обратите внимание, вы даже не нужно запись, достаточно сделать:

let fn' = fn 
for i in 0 .. 1000000000 do 
    a <- fn'(i, i) 
printfn "slow = %d" s.ElapsedMilliseconds 
+0

Извините, это не отвечает на ваш вопрос, почему компилятор не может его оптимизировать. –

+0

+1 Тем не менее, это прекрасная иллюстрация проблемы. – Shredderroy

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