C++ 范围/视图 vs. Rust 迭代器
似乎Rust的迭代器性能与C++的范围/视图之间存在相当大的差距,除非我遗漏了什么。
Rust代码:
```rust
use std::time::Instant;
fn expand_iota_views(input: &[i32]) -> impl Iterator<Item = i32> + '_ {
input
.iter()
.flat_map(|&n| 1..=n)
.flat_map(|n| 1..=n)
.flat_map(|n| 1..=n)
}
fn main() {
let input: Vec<i32> = (0..=50).collect();
let sample_result: Vec<i32> = expand_iota_views(&input).collect();
println!("Rust Result count: {}", sample_result.len());
let start = Instant::now();
let mut total_count = 0;
for _ in 0..1000 {
let result = expand_iota_views(&input);
total_count += result.count();
}
let duration = start.elapsed();
println!("Rust Total count (1000 iterations): {}", total_count);
println!("Rust Total time: {} microseconds", duration.as_micros());
println!(
"Rust Average per iteration: {:.2} microseconds",
duration.as_micros() as f64 / 1000.0
);
}
```
输出:
```
Rust Result count: 292825
Rust Total count (1000 iterations): 292825000
Rust Total time: 1025 microseconds
Rust Average per iteration: 1.02 microseconds
```
C++代码:
```cpp
#include <chrono>
#include <iostream>
#include <numeric>
#include <ranges>
#include <vector>
inline auto expandIotaViews(const std::vector<int>& input) {
auto iota_transform = [](const int number) {
return std::views::iota(1, number + 1);
};
return input
| std::views::transform(iota_transform)
| std::views::join
| std::views::transform(iota_transform)
| std::views::join
| std::views::transform(iota_transform)
| std::views::join;
}
int main() {
std::vector<int> input(51);
std::iota(input.begin(), input.end(), 0);
auto sample_result = expandIotaViews(input);
std::vector<int> result_vec;
for (auto val : sample_result) {
result_vec.push_back(val);
}
std::cout << "C++ Result count: " << result_vec.size() << std::endl;
auto start = std::chrono::high_resolution_clock::now();
size_t total_count = 0;
for (int i = 0; i < 1000; ++i) {
auto result = expandIotaViews(input);
total_count += std::ranges::distance(result);
}
auto end = std::chrono::high_resolution_clock::now();
auto duration =
std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "C++ Total count (1000 iterations): " << total_count << std::endl;
std::cout << "C++ Total time: " << duration.count() << " microseconds" << std::endl;
std::cout << "C++ Average per iteration: " << duration.count() / 1000.0 << " microseconds" << std::endl;
return 0;
}
```
输出:
```
C++ Result count: 292825
C++ Total count (1000 iterations): 292825000
C++ Total time: 174455 microseconds
C++ Average per iteration: 174.455 microseconds
```
查看原文
it seems there is a quite a bit of gap between the performance of Rust iterator and C++ ranges/views unless I am missing something.<p>https://godbolt.org/z/v76rcEb9n
https://godbolt.org/z/YG1dv4qYh<p>Rust:
<code>
use std::time::Instant;<p>fn expand_iota_views(input: &[i32]) -> impl Iterator<Item = i32> + '_ {
input
.iter()
.flat_map(|&n| 1..=n)
.flat_map(|n| 1..=n)
.flat_map(|n| 1..=n)
}<p>fn main() {
let input: Vec<i32> = (0..=50).collect();<p><pre><code> let sample_result: Vec<i32> = expand_iota_views(&input).collect();
println!("Rust Result count: {}", sample_result.len());
let start = Instant::now();
let mut total_count = 0;
for _ in 0..1000 {
let result = expand_iota_views(&input);
total_count += result.count();
}
let duration = start.elapsed();
println!("Rust Total count (1000 iterations): {}", total_count);
println!("Rust Total time: {} microseconds", duration.as_micros());
println!(
"Rust Average per iteration: {:.2} microseconds",
duration.as_micros() as f64 / 1000.0
);</code></pre>
}
</code><p>Output:
Rust Result count: 292825
Rust Total count (1000 iterations): 292825000
Rust Total time: 1025 microseconds
Rust Average per iteration: 1.02 microseconds<p>C++:
<code>
#include <chrono>
#include <iostream>
#include <numeric>
#include <ranges>
#include <vector><p>inline auto expandIotaViews(const std::vector<int>& input) {
auto iota_transform = [](const int number) {
return std::views::iota(1, number + 1);
};<p><pre><code> return input
| std::views::transform(iota_transform)
| std::views::join
| std::views::transform(iota_transform)
| std::views::join
| std::views::transform(iota_transform)
| std::views::join;</code></pre>
}<p>int main() {
std::vector<int> input(51);
std::iota(input.begin(), input.end(), 0);<p><pre><code> auto sample_result = expandIotaViews(input);
std::vector<int> result_vec;
for (auto val : sample_result) {
result_vec.push_back(val);
}
std::cout << "C++ Result count: " << result_vec.size() << std::endl;
auto start = std::chrono::high_resolution_clock::now();
size_t total_count = 0;
for (int i = 0; i < 1000; ++i) {
auto result = expandIotaViews(input);
total_count += std::ranges::distance(result);
}
auto end = std::chrono::high_resolution_clock::now();
auto duration =
std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "C++ Total count (1000 iterations): " << total_count
<< std::endl;
std::cout << "C++ Total time: " << duration.count() << " microseconds"
<< std::endl;
std::cout << "C++ Average per iteration: " << duration.count() / 1000.0
<< " microseconds" << std::endl;
return 0;</code></pre>
}
</code><p>Output:
C++ Result count: 292825
C++ Total count (1000 iterations): 292825000
C++ Total time: 174455 microseconds
C++ Average per iteration: 174.455 microseconds