use std::borrow::BorrowMut;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Instant};
use tokio::task;
struct Table {
data: HashMap<String, String>,
}
impl Table {
fn new() -> Self {
Self {
data: HashMap::new(),
}
}
async fn set(&mut self, name: String, value: String) {
self.data.insert(name, value);
}
fn get(&self, name: String) -> Option<String> {
return self.data.get(&name).cloned();
}
}
struct TableManager {
tables: HashMap<String, Table>,
}
impl TableManager {
fn new() -> Self {
return Self {
tables: HashMap::new(),
}
}
fn create_table(&mut self, name: String) {
self.tables.insert(name, Table::new());
}
async fn set(&mut self, name: String, key: String, value: String) {
self.tables.get_mut(&name).unwrap().set(key, value).await;
}
fn get(&self, name: String, key: String) -> Option<String> {
return self.tables.get(&name).unwrap().get(key);
}
fn delete_table(&mut self, name: String) {
self.tables.remove(&name);
}
}
#[tokio::main(flavor = "multi_thread", worker_threads = 1024)]
async fn main() {
let mut manager = Arc::new(TableManager::new());
manager.create_table("table1".to_string());
manager.create_table("table2".to_string());
manager.create_table("table3".to_string());
manager.create_table("table4".to_string());
let start = Instant::now();
let mut tasks = vec![];
for i in 0..3000000 {
let table_name = format!("table{}", i % 4 + 1);
let mut manager = manager.borrow_mut();
let task = task::spawn(async move {
manager.set(table_name, format!("{}", i), format!("value{}", i)).await;
});
tasks.push(task);
}
for task in tasks {
task.await.unwrap();
}
let elapsed = start.elapsed();
println!("Time taken to set 3,000,000 keys: {:?}", elapsed);
}
error[E0596]: cannot borrow data in an `Arc` as mutable
--> src\main.rs:79:13
|
79 | manager.set(table_name, format!("{}", i), format!("value{}", i)).await;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc`
1 - есть ли что-то быстрее, чем tokio
2 - правильно ли я использую tokio
3 - насколько хорошая с точки зрения производительности идея использовать Arc
4 - можно ли ускорить саму по себе структуру HashMap или только переписывать?
pub struct DashMap<K, V, S = RandomState> {
shift: usize,
shards: Box<[RwLock<HashMap<K, V, S>>]>,
hasher: S,
}
hashmap_no_capacity_format_key__3M
time: [1.4810 s 1.5362 s 1.5952 s]
hashmap_set_capacity_format_key__3M
time: [1.0688 s 1.0744 s 1.0804 s]
btree_format_key__3M time: [754.93 ms 843.10 ms 933.95 ms]
vec_set_apacity__3M time: [1.7122 ms 1.7309 ms 1.7655 ms]
dashmap_rayon_format_key__3M
time: [294.76 ms 303.70 ms 316.85 ms]
btree_known_key__3M time: [554.56 ms 556.18 ms 558.41 ms]
use std::{
collections::{BTreeMap, HashMap},
time::Instant,
};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn hashmap_no_capacity_format_key(n: usize) -> HashMap<String, usize> {
let mut map = HashMap::new();
for i in 0..n {
let key = format!("key_{i}");
map.insert(key, i);
}
map
}
fn hashmap_set_capacity_format_key(n: usize) -> HashMap<String, usize> {
let mut map = HashMap::with_capacity(n + 1);
for i in 0..n {
let key = format!("key_{i}");
map.insert(key, i);
}
map
}
fn btreemap_format_key(n: usize) -> BTreeMap<String, usize> {
let mut map = BTreeMap::new();
for i in 0..n {
let key = format!("key_{i}");
map.insert(key, i);
}
map
}
fn vec_set_capacity(n: usize) -> Vec<usize> {
let mut vector = Vec::with_capacity(n);
for i in 0..n {
vector.push(i);
}
vector
}
fn btreemap_known_key(keys: impl Iterator<Item = (String, usize)>) -> usize {
let mut map = BTreeMap::new();
for (k, v) in keys {
map.insert(k, v);
}
map.len()
}
fn dashmap_rayon_format_key(n: usize) -> dashmap::DashMap<String, usize> {
use rayon::prelude::*;
let map = dashmap::DashMap::with_capacity(n);
(0..n).into_par_iter().for_each(|i| {
let key = format!("key_{i}");
map.insert(key, i);
});
map
}
fn bench(c: &mut Criterion) {
c.bench_function("hashmap_no_capacity_format_key__3M", |b| {
b.iter(|| hashmap_no_capacity_format_key(black_box(3_000_000)))
});
c.bench_function("hashmap_set_capacity_format_key__3M", |b| {
b.iter(|| hashmap_set_capacity_format_key(black_box(3_000_000)))
});
c.bench_function("btree_format_key__3M", |b| {
b.iter(|| btreemap_format_key(black_box(3_000_000)))
});
c.bench_function("vec_set_apacity__3M", |b| {
b.iter(|| vec_set_capacity(black_box(3_000_000)))
});
c.bench_function("dashmap_rayon_format_key__3M", |b| {
b.iter(|| dashmap_rayon_format_key(black_box(3_000_000)))
});
c.bench_function("btree_known_key__3M", |b| {
b.iter_custom(|times| {
let mut total = vec![];
for _ in 0..times {
let mut keys = Vec::with_capacity(3_000_000);
for i in 0..3_000_000 {
keys.push((format!("key_{i}"), i));
}
let start = Instant::now();
black_box(btreemap_known_key(black_box(keys.drain(..))));
total.push(start.elapsed());
}
total.iter().sum()
});
});
}
criterion_group! {
name = benches;
config = Criterion::default().sample_size(10);
targets = bench
}
criterion_main!(benches);
#[tokio::main(flavor = "multi_thread", worker_threads = 1024)]
1024 - потеряли весь профит от небольшого числа потоков, теперь ОС будет распределять 1024 потока на небольшое количество ядер CPU.async fn set(&mut self, name: String, value: String) {
self.data.insert(name, value);
}
у этого метода нет ни одной причины быть асинхронным, операции с HashMap - чистый CPU-bound.fn main() {
let start = Instant::now();
let handles: Vec<_> = (0..4)
.map(|table_index| {
std::thread::spawn(move || {
let mut table = Table::new();
for i in (0..3000000).filter(|i| (i % 4 + 1) == table_index) {
table.set(format!("{}", i), format!("value{}", i));
}
table
})
})
.collect();
for handle in handles {
let _table = handle.join().unwrap();
// тут добавляем таблицы в менеджер
}
let elapsed = start.elapsed();
println!("Time taken to set 3,000,000 keys: {:?}", elapsed);
}
и даже это можно заморочиться и улучшить, например запускать потоков не больше std::thread::available_parallelism()
или оптимизировать счетчик для каждой таблицы ((0..3000000).filter(|i| (i % 4 + 1) == table_index)
), но это я оставлю Вам в качестве д/з.