1. thread_local! 导致跨线程缓存不可见(主要问题)

kline_py.rs 中 BSP_CACHE、KLINE_IDENTITY、BAR_IDENTITY 使用了 thread_local!。主线程调用 识别买卖点() →
  买卖点信息.add() 写入的是主线程的 PySet,backtrader 策略线程读取的是自己线程独立的空 PySet。

  修复:将三个缓存从 thread_local! 改为全局 static + std::sync::LazyLock<RwLock<HashMap<...>>>

  影响分析

  这些身份缓存的影响与 KLINE_IDENTITY/BAR_IDENTITY 不同——它们只影响 Python 对象身份(is
  比较),不直接影响数据内容(因为 Rust 数据通过 Arc 共享,读写都是同一份)。

  具体后果:
  - 不同线程访问同一个 Rust Arc 会得到不同的 Python wrapper 对象
  - a is b 跨线程比较返回 False,哪怕它们包装同一个底层 Rust 对象
  - 每个线程维护一份独立缓存,内存浪费(不过 wrapper 很小)
This commit is contained in:
YuWuKunCheng
2026-05-30 22:15:09 +08:00
parent 15dc44e8e0
commit b7c4e60420
12 changed files with 327 additions and 309 deletions
+33 -32
View File
@@ -566,6 +566,30 @@ impl 中枢 {
}
}
impl std::fmt::Display for {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let _str = self
.
.read()
.unwrap()
.iter()
.map(|d| format!("{}", d))
.collect::<Vec<_>>()
.join(", ");
write!(
f,
"{}({}, {}, 元素数量: {}, [{}], {} ===>>> {})",
self..read().unwrap(),
crate::utils::format_f64_g(self.()),
crate::utils::format_f64_g(self.()),
self..read().unwrap().len(),
_str,
self.(),
self.(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -575,13 +599,14 @@ mod tests {
use crate::types::;
fn _创建K线(: i64, : f64, : f64, : f64, : f64) -> K线 {
let mut k = K线::default();
k. = ;
k. = ;
k. = ;
k. = ;
k. = ;
k
K线 {
,
,
,
: ,
: ,
..Default::default()
}
}
fn _创建缠K(
@@ -710,7 +735,7 @@ mod tests {
.线(Arc::clone(&1));
assert!(.线.read().unwrap().is_some());
assert_eq!(
Arc::as_ptr(&*.线.read().unwrap().as_ref().unwrap()),
Arc::as_ptr(.线.read().unwrap().as_ref().unwrap()),
Arc::as_ptr(&1)
);
@@ -870,27 +895,3 @@ mod tests {
);
}
}
impl std::fmt::Display for {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let _str = self
.
.read()
.unwrap()
.iter()
.map(|d| format!("{}", d))
.collect::<Vec<_>>()
.join(", ");
write!(
f,
"{}({}, {}, 元素数量: {}, [{}], {} ===>>> {})",
self..read().unwrap(),
crate::utils::format_f64_g(self.()),
crate::utils::format_f64_g(self.()),
self..read().unwrap().len(),
_str,
self.(),
self.(),
)
}
}
+3 -3
View File
@@ -590,7 +590,7 @@ mod tests {
let config = ::default();
let obs_ref = ::new("btcusd".into(), 300, config);
let data = std::fs::read(&test_data_path()).unwrap();
let data = std::fs::read(test_data_path()).unwrap();
let size = 48;
for i in 0..data.len() / size {
@@ -720,7 +720,7 @@ mod tests {
#[test]
fn test_重复计算后结果一致() {
let data = std::fs::read(&test_data_path()).unwrap();
let data = std::fs::read(test_data_path()).unwrap();
let size = 48;
let = || {
@@ -764,7 +764,7 @@ mod tests {
let config = ::default();
let obs_ref = ::new("btcusd".into(), 300, config);
let data = std::fs::read(&test_data_path()).unwrap();
let data = std::fs::read(test_data_path()).unwrap();
let size = 48;
for i in 0..data.len() / size {
+51 -50
View File
@@ -960,6 +960,49 @@ impl 虚线 {
}
}
impl std::fmt::Display for 线 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if *self..read().unwrap() == "" {
write!(
f,
"笔({}, {}, {}, {}, 周期: {}, 数量: {})",
self..load(Ordering::Relaxed),
self.(),
self.,
self..read().unwrap(),
self...,
self..read().unwrap()...load(Ordering::Relaxed)
- self....load(Ordering::Relaxed)
+ 1
)
} else {
let = crate::algorithm::segment::线::(self);
let = crate::algorithm::segment::线::(self);
let _str = match {
Some(g) => format!("{}", g),
None => "None".to_string(),
};
let K线_str = match &*self.K线.read().unwrap() {
Some(k) => format!("{}", k),
None => "None".to_string(),
};
write!(
f,
"{}<{}, {}, {}, {}, {}, 数量: {}, 缺口: {}, {}>",
self..read().unwrap(),
self..load(Ordering::Relaxed),
,
self.(),
self.,
self..read().unwrap(),
self..read().unwrap().len(),
_str,
K线_str,
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -969,13 +1012,14 @@ mod tests {
/// 辅助:创建一根最小化的原始K线
fn _创建K线(: i64, : f64, : f64, : f64, : f64) -> K线 {
let mut k = K线::default();
k. = ;
k. = ;
k. = ;
k. = ;
k. = ;
k
K线 {
,
,
,
: ,
: ,
..Default::default()
}
}
/// 辅助:创建一根缠论K线
@@ -1239,46 +1283,3 @@ mod tests {
assert_eq!(, 300);
}
}
impl std::fmt::Display for 线 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if *self..read().unwrap() == "" {
write!(
f,
"笔({}, {}, {}, {}, 周期: {}, 数量: {})",
self..load(Ordering::Relaxed),
self.(),
self.,
self..read().unwrap(),
self...,
self..read().unwrap()...load(Ordering::Relaxed)
- self....load(Ordering::Relaxed)
+ 1
)
} else {
let = crate::algorithm::segment::线::(self);
let = crate::algorithm::segment::线::(self);
let _str = match {
Some(g) => format!("{}", g),
None => "None".to_string(),
};
let K线_str = match &*self.K线.read().unwrap() {
Some(k) => format!("{}", k),
None => "None".to_string(),
};
write!(
f,
"{}<{}, {}, {}, {}, {}, 数量: {}, 缺口: {}, {}>",
self..read().unwrap(),
self..load(Ordering::Relaxed),
,
self.(),
self.,
self..read().unwrap(),
self..read().unwrap().len(),
_str,
K线_str,
)
}
}
}
+8 -7
View File
@@ -320,13 +320,14 @@ mod tests {
use crate::types::;
fn _创建K线(: i64, : f64, : f64, : f64, : f64) -> K线 {
let mut k = K线::default();
k. = ;
k. = ;
k. = ;
k. = ;
k. = ;
k
K线 {
,
,
,
: ,
: ,
..Default::default()
}
}
fn _创建缠K(