Возможно ли передать право собственности, кроме как с помощью перемещения или коробки? [Дубликат]

Вот еще одно возможное решение:

let evenA = stride(from: 0, to: masterA.count, by: 2).map { masterA[$0] }
let oddA = stride(from: 1, to: masterA.count, by: 2).map { masterA[$0] }

Элементы «выбраны» непосредственно из четных / нечетных позиций в исходном массиве.

Сравнение производительности:

Мой простой, не очень сложный код для бенчмаркинга:

import Swift

let N = 10_000_000
let RUNS = 50

let masterA = (0..<N).map { $0 }

var times = (0.0, 0.0, 0.0, 0.0)
for _ in 1...RUNS {

    // filter+map (dfri)
    do {
        let start = Date()
        let evenA = masterA.enumerated().filter { $0.0 % 2 == 0 }.map{ $0.1 }
        let oddA = masterA.enumerated().filter { $0.0 % 2 != 0 }.map{ $0.1 }
        let time = Date().timeIntervalSince(start)
        times.0 += time
    }

    // flatMap (dfri)
    do {
        let start = Date()
        let evenA = masterA.enumerated().flatMap { $0 % 2 == 0 ? $1 : nil }
        let oddA = masterA.enumerated().flatMap { $0 % 2 != 0 ? $1 : nil }
        let time = Date().timeIntervalSince(start)
        times.1 += time
    }

    // stride+map (me)
    do {
        let start = Date()
        let evenA = stride(from: 0, to: masterA.count, by: 2).map { masterA[$0] }
        let oddA = stride(from: 1, to: masterA.count, by: 2).map { masterA[$0] }
        let time = Date().timeIntervalSince(start)
        times.2 += time
    }

    // loop (Keiwan)
    do {
        let start = Date()
        var evenA = [Int]()
        var oddA = [Int]()

        for (index, element) in masterA.enumerated() {
            if index % 2 == 0 {
                evenA.append(element)
            } else {
                oddA.append(element)
            }
        }
        let time = Date().timeIntervalSince(start)
        times.3 += time
    }
}

print(N, RUNS)
print(times.0/Double(RUNS), times.1/Double(RUNS), times.2/Double(RUNS), times.3/Double(RUNS))

Результаты: (В MacBook, работающем в режиме деблокирования)

#elements   filter+map  flatMap   stride+map  loop
10,000      0.0001      0.00008   0.00004     0.00004
100,000     0.0016      0.0008    0.0004      0.0004
1,000,000   0.0295      0.0136    0.0090      0.0091
10,000,000  0.3025      0.1332    0.0909      0.1250
13
задан Shepmaster 26 July 2016 в 00:20
поделиться

1 ответ

Учитывая, что в Rust (в отличие от C или C ++) адрес значения не считается существенным, в терминах language нет ничего, что предотвращало бы исключение копии.

Однако сегодня rustc ничего не оптимизирует: все оптимизации делегированы LLVM, и, похоже, вы столкнулись с ограничением оптимизатора LLVM здесь (неясно, связано ли это ограничение с LLVM, близким к семантике C или просто упущение).

Итак, есть два способа улучшения генерации кода для этого:

  • преподавание LLVM для выполнения этой оптимизации (если возможно)
  • преподавание rustc для выполнения этой оптимизации (теперь пакеты оптимизации проходят до rustc, когда у них есть MIR)

, но на данный момент вы можете просто захотеть избежать выделения таких больших объектов в стеке, вы можете Box это например.

19
ответ дан Matthieu M. 18 August 2018 в 11:21
поделиться
  • 1
    Говоря о проходах оптимизации MIR, первый из них будет простым прохождением распространения цели: github.com/rust-lang/rust/pull/34693 . Проблема отслеживания - github.com/rust-lang/rust/issues/32966 . – eddyb 25 July 2016 в 17:05
  • 2
    Вместо того, чтобы просто избегать распределения стека, было бы лучше предположить, что движение будет оптимизировано и только поле позже, если это не так. Большую часть времени в Rust вы не должны думать о попытке избежать копирования вещей. – Michael Younkin 26 July 2016 в 02:48
  • 3
    @MichaelYounkin: Я частично согласен. Проблема в том, что большие объекты, скопированные несколько раз в стек, легко приводят к переполнению стека, особенно с целевыми объектами Debug, где оптимизации не возникают. Если буфер очень велик, стоимость динамического распределения должна быть затмевана стоимостью инициализации самого буфера. – Matthieu M. 26 July 2016 в 10:31
  • 4
    @MatthieuM, выделяя его в куче, очень хорошо, но по моему опыту даже запись Box :: new (BigStruct :: new ()) сначала выделяет BigStruct в стеке (в BigStruct :: new), а затем копирует его в куча (в поле: новый). Или я чего-то не хватает? – Pierre-Antoine 22 December 2017 в 08:29
  • 5
    @ Пьер-Антуан: В Отлаге, да, пока; вот почему размещение new так популярно. В Release все же, вероятно, будет оптимизирована копия стека, но это может привести к переполнению стека в Debug, которые не позволяют вам тестировать ваш код :( – Matthieu M. 25 December 2017 в 12:16
Другие вопросы по тегам:

Похожие вопросы: