#swift #performance
#swift #Производительность
Вопрос:
Если бы я хотел проверить, соответствует ли переменная протоколу, есть два способа сделать это:
protocol Computer { }
struct Mac: Computer { }
let device = Mac()
device is Computer // option 1
(device as? Computer) != nil // option 2
С точки зрения чистой производительности, какой вариант быстрее и на сколько? Давайте представим, что нам не нужно приведенное значение, мы просто хотим знать, соответствует ли оно. Я бы предположил, что первый вариант быстрее, но это всего лишь предположение.
Комментарии:
1. Xcode поставляется с инструментами, идеальным инструментом для проверки вашей гипотезы…
2. Такая простая операция не должна иметь последствий для производительности в большинстве случаев, поэтому я не вижу никаких причин даже для рассмотрения безопасного приведения, а затем
nil
проверки, действительно ли вам не нужно приведенное значение. Просто используйтеis
и не пытайтесь выполнять преждевременную оптимизацию.3. Гипотетически, предположим,
(device as? Computer) != nil
было быстрее. Насколько быстрее вам нужно было бы быть, чтобы вы чувствовали себя оправданным, заменяя что-то такое простое, какdevice is Computer
, чем-то таким неприятным, как(device as? Computer) != nil
?4. Это был скорее вопрос из любопытства. Я уверен, что в реальном мире мне было бы трудно найти случай, когда это имело бы значение.
5. вы действительно могли бы использовать инструментальные средства, написать цикл, который выполняет строку миллион раз, и проверить, сколько времени это заняло
Ответ №1:
Я только что провел быстрый тест, и разница в производительности незначительна. Это не идеальный способ тестирования, но я использовал следующий код playground:
import Cocoa
func executionTimeInterval(block: () -> Void) -> CFTimeInterval {
let start = CACurrentMediaTime()
block()
return CACurrentMediaTime() - start
}
protocol Computer {}
struct Mac: Computer {}
// Mark as `Any` in case the compiler optimises the fact that the checks will always be true
let device: Any = Mac()
let iterations = 10000
var cumulativeTime = CFTimeInterval(0)
for _ in 0..<iterations {
cumulativeTime = executionTimeInterval {
_ = device is Computer
}
}
cumulativeTime / CFTimeInterval(iterations) // option1
cumulativeTime = 0
for _ in 0..<iterations {
cumulativeTime = executionTimeInterval {
_ = (device as? Computer) != nil
}
}
cumulativeTime / CFTimeInterval(iterations) // option2
Комментарии:
1. Спасибо за тест! Я получил почти идентичный результат. Даже при переключении второго теста на назначение, а затем на проверку, я получил разницу всего в 2 раза.
2. Кстати, при полной оптимизации
_ = device is Computer
часть, вероятно, будет удалена полностью. Это не так просто проверить. Тестирование производительности на игровых площадках само по себе является большой проблемой.3. Вы действительно не можете тестировать производительность на игровых площадках. Вроде бы, вообще.
4. @Alexander Я запустил это в обычной программе и получил те же результаты. Я пробовал как с оптимизацией, так и без нее, и вы могли видеть, что эти вызовы оптимизируются (для этого есть подходящий термин, но не могу его вспомнить).