Expand description
§Action Dispatch
一个通用的基于属性宏的 Action 注册与分发系统
§特性
- ✅ 声明式注册:使用
#[action(...)]属性宏标记处理函数 - ✅ 正则匹配:支持正则表达式匹配 key
- ✅ 优先级控制:支持设置 action 优先级
- ✅ 类型安全:编译期类型检查,无需序列化
- ✅ 线程安全:完全线程安全,支持多线程并发
- ✅ 全局同步模式:支持全局排他执行,阻塞所有其他 dispatch
- ✅ 零成本抽象:编译期注册,运行时几乎无开销
§核心概念
§全局同步锁(Global Sync Lock)
系统维护一个全局互斥锁,所有 dispatch 调用都会竞争此锁:
-
sync = false(默认):拿锁 → 匹配 → 释放锁 → 执行- 支持多个 action 并发执行
-
sync = true:拿锁 → 匹配 → 不释放锁 → 执行 → 完成后释放- 该 action 执行期间,所有其他 dispatch 请求都会被阻塞
- 适用于关键操作,如数据库迁移、配置更新等
§快速开始
use action_dispatch::{action, dispatch};
#[derive(Clone)]
struct MyEvent {
user_id: u64,
action: String,
}
// 普通 action,支持并发
#[action(regex = r"user/\d+/read", priority = 5, sync = false)]
fn handle_read(event: MyEvent) {
println!("读取用户 {}", event.user_id);
}
// 关键 action,全局同步执行
#[action(regex = r"user/\d+/update", priority = 10, sync = true)]
fn handle_update(event: MyEvent) {
println!("更新用户 {}(阻塞所有其他操作)", event.user_id);
std::thread::sleep(std::time::Duration::from_secs(2));
}
fn main() {
// 直接分发事件(首次调用会自动初始化注册表)
dispatch("user/123/read", MyEvent {
user_id: 123,
action: "read".to_string(),
}).unwrap();
dispatch("user/456/update", MyEvent {
user_id: 456,
action: "update".to_string(),
}).unwrap();
}§多线程示例
use action_dispatch::{action, dispatch};
use std::thread;
#[derive(Clone)]
struct Event { id: u64 }
#[action(regex = r"normal/.*", sync = false)]
fn handle_normal(event: Event) {
println!("并发执行: {}", event.id);
}
#[action(regex = r"critical/.*", sync = true)]
fn handle_critical(event: Event) {
println!("独占执行: {}", event.id);
thread::sleep(std::time::Duration::from_secs(1));
}
fn main() {
let handles: Vec<_> = (0..10).map(|i| {
thread::spawn(move || {
if i % 2 == 0 {
dispatch("normal/task", Event { id: i }).unwrap();
} else {
dispatch("critical/task", Event { id: i }).unwrap();
}
})
}).collect();
for h in handles {
h.join().unwrap();
}
}§参数说明
§#[action(...)] 参数
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
regex | &str | ✅ | - | 匹配 key 的正则表达式 |
priority | i32 | ❌ | 0 | 优先级,数值越大优先级越高 |
description | &str | ❌ | "" | 描述信息 |
sync | bool | ❌ | false | 是否启用全局同步执行模式 |
§函数签名要求
- 必须是自由函数(不在 impl 块中)
- 必须恰好有一个参数:
fn(T)或fn(&T) - 所有 action 必须使用相同的事件类型
T - 返回值不限
§性能特点
- 编译期注册:使用
inventorycrate 在编译期收集所有 handler - 零动态分配:action 列表在程序启动时初始化,之后只读
- 高效匹配:使用编译后的正则表达式,支持缓存
- 最小锁竞争:
sync = false的 action 快速释放锁
§错误处理
use action_dispatch::{dispatch, DispatchError};
match dispatch("unknown/key", event) {
Ok(()) => println!("分发成功"),
Err(DispatchError::NoMatch) => println!("没有匹配的 action"),
Err(DispatchError::Poisoned) => println!("锁已被污染"),
}§并发控制
§全局单线程模式
可以配置全局并发策略,强制所有 dispatch 串行执行:
use action_dispatch::set_single_thread_mode;
fn main() {
// 启用单线程模式(调试/嵌入式系统)
set_single_thread_mode(true);
// 即使在多线程环境中,所有 dispatch 也会串行执行
dispatch("key1", event1).unwrap();
dispatch("key2", event2).unwrap();
}§使用场景
| 场景 | 配置 | 说明 |
|---|---|---|
| 生产环境 | set_single_thread_mode(false) | 默认,启用并发 |
| 调试模式 | set_single_thread_mode(true) | 简化并发问题排查 |
| 嵌入式系统 | set_single_thread_mode(true) | 单核 CPU 无需并发 |
| 性能测试 | 动态切换 | 对比单/多线程性能 |
§查询当前模式
use action_dispatch::is_single_thread_mode;
if is_single_thread_mode() {
println!("当前为单线程模式");
} else {
println!("当前为多线程模式");
}§调试工具
use action_dispatch::list_actions;
// 列出所有已注册的 action
for action in list_actions() {
println!("Action: {} (优先级: {}, sync: {})",
action.regex, action.priority, action.sync);
}§注意事项
- 避免死锁:
sync = true的 action 中不要再调用dispatch - 性能考虑:谨慎使用
sync = true,会阻塞所有其他操作 - 类型一致性:所有 action 必须使用相同的事件类型
- 正则性能:复杂的正则表达式可能影响匹配速度
§License
MIT OR Apache-2.0
Structs§
- Action
Info - Action 信息(用于调试和监控)
Enums§
- Dispatch
Error - 分发错误类型
Functions§
- dispatch
- 事件分发函数
- is_
single_ thread_ mode - 获取当前的并发模式
- list_
actions - 获取所有已注册的 action 信息(用于调试)
- set_
single_ thread_ mode - 配置全局并发策略
Attribute Macros§
- action
- #[action(…)] 属性宏