Есть ли способ избежать сохранения / выпуска Swift для высокопроизводительного кода? - PullRequest
0 голосов
/ 22 февраля 2019

Я хотел написать 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

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]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...