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:
@@ -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.武(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user