Я хотел написать Swift-версию классической структуры данных кэша, которая использует массив до определенного настраиваемого предела, а затем переключается на карту [2].К сожалению, характеристики производительности, которые я получаю при написании еще более простой структуры данных, заставляют меня думать, что в данный момент это не выполнимо быстро.
Рассмотрим этот фрагмент кода:
import Foundation
let aKey = 196
var cache: [(Int, String)] = []
for _ in 0..<1_000_000_000
{
var t: String?
for (k, v) in cache
{
if k == aKey
{
t = v
break
}
}
if t == nil
{
let str = "some cache value with key=\(aKey)"
cache.append((aKey, str))
t = str
}
}
Это занимает около0,785 с.
Эта другая программа, которая должна быть примерно эквивалентна:
import Foundation
struct DummyCache<K:Hashable, V>
{
var array:[(K, V?)] = []
subscript(index: K) -> V?
{
get
{
for (k, v) in array
{
if k == index
{
return v
}
}
return nil
}
set(newValue)
{
array.append((index, newValue))
}
}
}
let aKey = 196
var cache: DummyCache<Int, String> = DummyCache()
cache[aKey] = "some cache value with key=\(aKey)"
for _ in 0..<1_000_000_000
{
var t: String? = cache[aKey]
}
На самом деле в 45 раз медленнее!(около 35,532 с)
При профилировании этого кода я вижу, что большая часть времени проводится в быстром режиме: ![profile](https://i.stack.imgur.com/eFX4J.png)
IsЕсть ли способ улучшить производительность этого?
[2] Для записи вот структура данных, которую я имел в виду:
import Foundation
struct Cache<K:Hashable, V>
{
let limit: Int
var array:[(K, V)]? = nil
var map: [K:V]? = nil
let buildValueFromKey: (K) -> V
init(limit: Int = 20, buildValueFromKey:@escaping (K) -> V) //optimal limit depends, must conduct tests to find optimal value
{
self.limit = limit
self.buildValueFromKey = buildValueFromKey
}
subscript(index: K) -> V
{
mutating get
{
if var map = map
{
if let res = map[index]
{
return res
}
else
{
let res = buildValueFromKey(index)
map[index] = res
return res
}
}
else //array mode
{
if array == nil
{
let res = buildValueFromKey(index)
array = [(index, res)]
return res
}
//else
for (k, v) in array! //can't be null at that point
{
if k == index
{
return v
}
}
// array does not contain index at this point, create & append it
let res = buildValueFromKey(index)
array!.append((index, res))
return res
}
}
}
}
let aKey = 196
var cache: Cache<Int, String> = Cache{ "some cache value with key=\($0)" }
for _ in 0..<1_000_000_000
{
var t: String? = cache[aKey]
}