Каков наиболее эффективный способ создания изменяемого фрагмента из изменяемых фрагментов в Rust?

Я использую функцию внешней библиотеки, которая получает на вход тип:
&mut [&mut [f32]], который должен представлять собой двумерный массив фиксированных размеров.

Для повышения производительности я хотел бы создать одномерный массив, чтобы все данные постоянно находились в памяти, и преобразовать их в указанную выше форму.

Однако из-за отсутствия опыта работы с Rust у меня мало проблем, и мне интересно, каким «путем Rust» можно достичь моей цели.

Один из способов, о котором я мог подумать, — это создать новый Vec, повторить одномерный массив и перенести в него каждый фрагмент, но это похоже на пустую трату памяти.

Заранее спасибо.

Вы не можете преобразовать vec<f32> в &mut [&mut [f32]], поскольку данные имеют неправильную форму. Например, вы можете использовать Vec<&mut [f32]>, вероятно, это будет эффективно, только если внешний размер небольшой. Вы можете использовать такую ​​библиотеку , которая определяет для вас такие представления.

user2407038 25.04.2024 22:07

Почему одномерный массив будет более производительным в вашем случае? Как именно вы по-другому организуете массив в памяти?

Codebling 25.04.2024 22:25

К вашему сведению, функции обычно не должны принимать &mut [&mut [T]], они должны принимать &mut [impl AsMut<[T]>]. Если это ваш единственный вариант, то ваша идея создать новый Vec хороша, и если под «исправленным» вы подразумеваете исправленные во время компиляции, то вы можете поместить их в массив.

drewtato 25.04.2024 22:26

Если у вас есть данные в одном непрерывном векторе, вы можете использовать chunks_exact_mut для получения итератора над каждым изменяемым подсрезом, но вам придется собрать это в другой Vec, чтобы передать полученный срез в библиотека.

eggyal 26.04.2024 06:06

@Codebling, возможно, я ошибаюсь, но если я создам 2d-массив, гарантированно ли он будет лежать в том же фрагменте памяти?

barak1412 26.04.2024 09:20

@eggyal, не могли бы вы опубликовать ответ с примером вашего решения?

barak1412 26.04.2024 09:21

barak1412 да! 1D целых чисел содержит все целые числа подряд. «2D-массив» на самом деле представляет собой просто 1D-массив 1D-массивов. Когда вы спрашиваете, всегда ли он будет находиться в одном и том же участке памяти, ответ — да. Если вы спрашиваете, какие элементы будут смежными, элементы каждой «строки» будут смежными, и каждая строка также будет смежной. Если вам нужен конкретный макет, который вам нужен, вы можете оптимизировать его дальше.

Codebling 26.04.2024 19:51

По моему скромному мнению, для каждого проекта существует планка производительности, и пока кто-то ожидает, что его код будет оставаться выше этого уровня производительности, ему следует сосредоточиться на чистом и удобном в сопровождении коде, прежде чем сосредоточиться на оптимизации.

Codebling 26.04.2024 19:52

@Codebling Я согласен с тобой. Полезно знать о 2d-массиве, спасибо!

barak1412 27.04.2024 20:22
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
9
108
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы не можете превратить Vec<f32> в &mut [&mut [f32]], но вы можете дешево построить &mut [&mut [f32]] из Vec<f32>, сначала превратив его в &mut [f32], а затем просто обернув его в другой &mut [].

fn main() {
    let mut v = vec![1.0, 2.0, 3.0];
    let inner = &mut *v;
    add(&mut [inner], 10.0);
    println!("{v:?}");
    // [11.0, 12.0, 13.0]
}

fn add(arr: &mut [&mut [f32]], addend: f32) {
    for inner in arr {
        for x in inner.iter_mut() {
            *x += addend;
        }
    } 
}

Как срез, сгенерированный таким образом, «представляет собой двумерный массив фиксированных размеров». которые отличаются от (1, N)?

cafce25 26.04.2024 06:10
Ответ принят как подходящий

Если у вас есть данные в одном непрерывном срезе (например, в Vec), вы можете использовать chunks_exact_mut для получения итератора по каждому изменяемому подсрезу, но вам придется собрать это в (другой) Vec чтобы передать полученный фрагмент в библиотеку. Например:

/// Given the row-first two-dimensional array represented by
/// `contiguous_rows_of_cols`, return (in order) each row as a subslice.
fn to_vec_of_slices<T>(contiguous_rows_of_cols: &mut [T], cols: usize) -> Vec<&mut [T]> {
    contiguous_rows_of_cols.chunks_exact_mut(cols).collect()
}

Смотрите на детской площадке.

Другие вопросы по теме